---
title: "MariaDB to SQL Server data types"
description: "Every MariaDB data type that SQL Server stores differently, what the converter writes for it, when, and the report line."
canonical: https://intosql.com/docs/types/mariadb-to-sql-server
last_updated: 2026-10-15
---

# MariaDB to SQL Server data types

Each row is a type from MariaDB that SQL Server stores differently: what the SQL Server script gets, why, and the line the report writes about it. The rows come from the converter's own rules, so this page matches what it does.

**Convert in the browser:** [MariaDB to SQL Server](/mariadb-to-sql-server) opens the converter set up for this pair. The [MariaDB to SQL Server migration guide](/docs/migrations/mariadb-to-sql-server) covers dumping, loading and the rules for keys, indexes and names.

A report line is a fix when the converter changed something and lists it, or a problem when a value or object is worth a look.

## Numbers

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| UNSIGNED integers | TINYINT UNSIGNED as tinyint; the others the next wider integer with a CHECK that it isn't negative, BIGINT UNSIGNED as bigint when every value fits, else decimal(38,0) | SQL Server has no unsigned integers except tinyint, which is 0 to 255. A wider type holds the whole unsigned range, and the check keeps negative values out as MySQL did. | `unsigned_widened` (fix) |
| ZEROFILL and display widths | dropped | Zero padding is a way of showing a number, not part of it. The numbers are kept; format them when you read them if the padding matters. | `zerofill_dropped` (fix) |
| FLOAT(M,D) | real or float, without the scale | SQL Server floats have no fixed scale. The stored values are copied as they are. | `float_scale_dropped` (fix) |
| DECIMAL(p,s) | decimal(p,s) up to 38 digits; nvarchar beyond | SQL Server's decimal holds 38 digits. Wider decimals are kept as text so every digit stays exact. | `decimal_as_text` (fix) |

## Booleans and bits

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| TINYINT(1), BOOL | bit when every value is 0 or 1, else smallint | MySQL's BOOL is a TINYINT(1) that can hold any number from -128 to 127. A column that only holds 0 and 1 becomes bit; one that holds 2 or -1 stays a number so no value changes meaning. | `bool_kept_numeric` (fix) |
| BIT(1), BIT(n) | bit; bigint up to 63 bits; decimal(20,0) for BIT(64) | A single bit is a yes or no; wider bit fields are stored as the number their bits make. | None |

## Text

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| CHAR(n), VARCHAR(n) | nvarchar(n) | nvarchar holds every character on every supported version, and MySQL returns CHAR values without trailing spaces, as nvarchar keeps them. | None |
| text with characters past U+FFFF (emoji) in VARCHAR(n) | nvarchar(2n), or nvarchar(max) past 4000 | nvarchar counts UTF-16 units and an emoji takes two, so the column gets room for every value. | `text_length_widened` (fix) |
| NUL bytes in text | kept | nvarchar can hold a NUL character, so the value is copied as it is. | None |
| text that isn't valid in its character set | the bad bytes as the replacement character | Text has to be read as characters to be written as nvarchar. | `invalid_utf8_replaced` (problem) |

## Enums and sets

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| ENUM | nvarchar with a CHECK of its values | Text with a check keeps the same values. | None |
| ENUM holding '' (MySQL's error value) | the empty value allowed by the check | MySQL stores an empty string when an invalid value goes into an ENUM in a lenient SQL mode. Those rows are kept and the check allows them. | `enum_invalid_value` (fix) |
| ENUM holding values outside its list | no CHECK | Values the list doesn't name would fail the check, so the check isn't created. | `enum_check_skipped` (problem) |
| SET | nvarchar as MySQL writes it ('a,b') | SQL Server has no arrays; the text is the one MySQL returns. | None |

## Dates and times

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULL | SQL Server only stores real calendar dates. MySQL keeps zero and impossible dates when its SQL mode allows them; they become NULL and the report counts them. | `invalid_date_null` (problem) |
| DEFAULT '0000-00-00' | no default | A default SQL Server can't store is left out rather than replaced with a made-up date. | `zero_date_default` (fix) |
| TIME | time when every value is within a day, else nvarchar | MySQL's TIME is a duration from -838:59:59 to 838:59:59; SQL Server's time is a time of day. A column with longer or negative values keeps them as text. | `time_as_interval` (problem) |
| YEAR | smallint with a CHECK of its range | SQL Server has no year type; the check keeps the same values MySQL allows. | None |
| DATETIME | datetime2 | A DATETIME is a wall-clock reading without a time zone, like datetime2. | None |
| TIMESTAMP | datetimeoffset in the time zone the dump states, UTC when it states none | A TIMESTAMP is a moment. Dumps state the zone they wrote it in (mysqldump writes UTC); without that, the values are read as UTC and the report says so. | `timestamp_zone_assumed` (problem) |

## Binary

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| BINARY, VARBINARY, BLOB | binary, varbinary, varbinary(max) | Bytes stay bytes. | None |

## JSON, spatial and other types

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| JSON | nvarchar(max) | SQL Server's JSON functions read JSON from text. An ISJSON check would refuse scalar values such as 1 or "x" before SQL Server 2022, which MySQL keeps. | None |
| GEOMETRY, POINT, POLYGON... | geometry, with each value's SRID | SQL Server's own geometry type keeps every shape and its spatial reference system. | None |
| INET4, INET6, UUID (MariaDB) | nvarchar(39), uniqueidentifier | uniqueidentifier is SQL Server's UUID; addresses are kept as text. | None |
| geometries in a dump without CREATE TABLE | geometry | MySQL's geometry format is recognised from the values. | None |
| types IntoSQL doesn't know | nvarchar(max) | Text holds any value; change the type after loading. | `unknown_type` (problem) |
| values that don't fit their column | NULL | A damaged or hand-written dump can hold values its column can't; they become NULL so the rest loads. | `invalid_value_null` (problem) |
| unreadable geometries | NULL | Bytes that aren't a geometry can't be stored as one. | `bad_geometry` (problem) |
| VECTOR(n) (MariaDB 11.7+) | nvarchar(max) with the floats as a JSON array | Only SQL Server 2025 has a vector type; a JSON array keeps every float on every version. | `type_replaced` (fix) |

## Counters and identities

| In MariaDB | In SQL Server | Why | Report line |
| --- | --- | --- | --- |
| AUTO_INCREMENT | IDENTITY, with the counter set past the copied ids | The copied ids load with IDENTITY_INSERT, and the counter continues after the highest one or the dump's AUTO_INCREMENT, whichever is higher. | None |
| MyISAM AUTO_INCREMENT on the second column of a key | one counter for the table | MyISAM counts per group of the key's first column; SQL Server has one counter per table. | `myisam_group_autoincrement` (problem) |

## Other pairs

- MariaDB into [PostgreSQL](/docs/types/mariadb-to-postgresql), [MySQL](/docs/types/mariadb-to-mysql), [MariaDB](/docs/types/mariadb-to-mariadb), [SQLite](/docs/types/mariadb-to-sqlite), [Oracle](/docs/types/mariadb-to-oracle)
- Into SQL Server from [MySQL](/docs/types/mysql-to-sql-server), [PostgreSQL](/docs/types/postgresql-to-sql-server), [SQL Server](/docs/types/sql-server-to-sql-server), [SQLite](/docs/types/sqlite-to-sql-server), [Oracle](/docs/types/oracle-to-sql-server)
- [Every pair](/docs/types#from-one-database-to-another)
