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

# SQL Server to MySQL data types

Each row is a type from SQL Server that MySQL stores differently: what the MySQL 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:** [SQL Server to MySQL](/sql-server-to-mysql) opens the converter set up for this pair. The [SQL Server to MySQL migration guide](/docs/migrations/sql-server-to-mysql) 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 SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| decimal(p,s), money, smallmoney | decimal(p,s); money as decimal(19,4) | decimal holds 65 digits, more than SQL Server's 38, so every value is exact. | None |

## Booleans and bits

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| bit | tinyint(1) | MySQL's BOOLEAN is TINYINT(1): 1 and 0, as bit holds them. | None |

## Text

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| char(n), varchar(n), nchar(n), nvarchar(n), varchar(max), text | char(n), varchar(n) up to 1024 characters, text types beyond | Text keeps every character as utf8mb4. A column in a key is varchar(768) at most, the longest a key holds, and so is text with a default, which MySQL 5.7 gives only to varchar. | None |
| NUL characters in text | kept | The value is copied with the NUL character escaped. | None |
| text that isn't valid in its encoding | the bad bytes as the replacement character | The script is UTF-8 and every value has to be valid text. | `invalid_utf8_replaced` (problem) |

## Dates and times

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| datetime, datetime2, smalldatetime | datetime(p) | A datetime is a wall-clock reading in both. | None |
| datetime2(7), time(7) and datetimeoffset(7) | six digits of a second, the seventh cut | MySQL keeps microseconds; the seventh digit (100 nanoseconds) is cut, never rounded, so no value moves to the next second or day. | `fraction_cut` (fix) |
| datetimeoffset | datetime(p) in UTC | MySQL's TIMESTAMP only reaches 2038, so moments are stored as datetime in UTC, the same instant whatever offset each value had. | `moments_as_utc` (fix) |
| time | time(p) | The same times of day. | None |
| dates before the year 1000 | NULL | MySQL stores years 1000 to 9999, and SQL Server goes back to the year 1. Those values become NULL and the report counts them. | `date_out_of_range` (problem) |

## Binary

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| binary, varbinary, image | binary(n), varbinary(n) and blob types | Bytes stay bytes. | None |
| rowversion, timestamp | blob, empty | SQL Server sets a row version by itself and SSMS scripts no values for it. | `rowversion_empty` (fix) |

## JSON, spatial and other types

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| json (SQL Server 2025) | json | The same JSON values, which MySQL's JSON functions read. | None |
| uniqueidentifier | char(36) | The same identifiers, written in lowercase. | None |
| geometry, geography | blob with SQL Server's own bytes | SSMS writes spatial values in SQL Server's serialization, which is kept byte for byte. | `spatial_as_native` (fix) |
| xml, sql_variant, hierarchyid, vector | longtext | MySQL has no equivalent type; xml and sql_variant keep each value's text and hierarchyid its path, such as /1/2/. | `type_replaced` (fix) |
| types IntoSQL doesn't know | longtext | Text holds any value; change the type after loading. | `unknown_type` (problem) |

## Counters and identities

| In SQL Server | In MySQL | Why | Report line |
| --- | --- | --- | --- |
| IDENTITY | AUTO_INCREMENT, continuing after the highest id | The column that leads the primary key counts; the counter continues after the highest id. | None |
| IDENTITY columns that don't lead the primary key | a plain integer | MySQL counts one column per table, at the start of a key; any other keeps its values without a counter. | `counter_dropped` (problem) |

## Other pairs

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