Skip to content
adapters.io

SQL Server to MySQL migration tools and converters compared on what actually lands

Ten ways to move a SQL Server database into MySQL, judged on the rows that arrive. MySQL's own converter publishes a type map that sends SQL Server's TIMESTAMP, a binary version counter, into a MySQL date column. That is where this route goes wrong, and it goes wrong quietly.

The live demo needs no card, and Starter is $49 a month.

Field mapping auto-plugged · tap a port to rewire

5 sample records ready

Vendor documentation read 30 September 2026

Which SQL Server to MySQL migration tool should you use?

For a one-time move into RDS or Aurora MySQL, use AWS SCT for the schema and DMS for the data. For a small database, the MySQL Workbench Migration Wizard costs nothing. For stored-procedure heavy schemas, use a T-SQL converter such as SQLines or Ispirer. For an ongoing sync, use a tool that lets you declare the MySQL columns. Whichever you pick, correct five type mappings by hand first.

Four SQL Server columns and what a default mapping turns them into in MySQL, with rowversion as a date, money as a whole number, datetimeoffset without its offset and datetime2 rounded. SQL SERVER MYSQL, DEFAULT MAP rowversion money datetimeoffset datetime2(7) TIMESTAMP a counter in a date column DECIMAL bare means (10,0), no cents DATETIME offset truncated DATETIME(6) what to declare instead
Three default mappings that load without an error, and the one correction that shows the pattern.

This route sits under our data migration tools guide. If PostgreSQL is still an option for the target, the same SQL Server source with a different set of type rules is compared on SQL Server to PostgreSQL migration tools.

Eight documented defaults that change your data between SQL Server and MySQL

Each row sets a tool's own documentation against what Microsoft or MySQL say about the same type. The first five come from the type mapping published in the MySQL Workbench manual, which is why they are trusted: it is MySQL's own tool, and nobody reads the Microsoft page on rowversion before they run it.

Tool and setting What the documentation says Why it matters to a buyer What we would ship
Workbench, TIMESTAMP and ROWVERSION The Workbench manual maps both SQL Server TIMESTAMP and ROWVERSION to MySQL TIMESTAMP. Microsoft says rowversion "does not preserve a date or a time" and timestamp is its synonym, a binary(8) counter. A version counter lands in a date column. Under strict mode the load rejects it; with strict mode off it becomes a zero date. Either way the optimistic-concurrency check the app relied on is gone. BINARY(8), or drop it
Workbench, MONEY Mapped to "DECIMAL" with no precision listed. MySQL says a DECIMAL without precision is DECIMAL(10,0), and "the default value of M is 10." If the generated DDL carries the bare type, every balance loses its cents and anything above 9,999,999,999 overflows. SUM checks disagree while row counts match. DECIMAL(19,4) in the DDL
Workbench, DATETIMEOFFSET Mapped to MySQL DATETIME. Microsoft says converting datetimeoffset to a type without an offset copies the date and time and "the time zone is truncated." Rows written from New York and Los Angeles now look simultaneous when they were three hours apart. Nothing fails, and every report grouped by hour is quietly wrong. Convert to UTC first, keep the offset
Workbench, DATETIME2 Mapped to MySQL DATETIME. Microsoft documents datetime2 at 7 fractional digits by default. MySQL allows at most 6, and a DATETIME with no precision has none. Timestamps round to the second or to the microsecond. At year end, 23:59:59.6 on 31 December rounds into January and moves revenue into the next fiscal year. DATETIME(6) on every column
Workbench, UNIQUEIDENTIFIER Mapped to VARCHAR(64), with the note "Unique flag set in MySQL. No specific support for inserting unique identifier values." A GUID primary key is fine. A GUID foreign key repeats by design, and a unique index on it rejects every second order for the same customer. BINARY(16) or CHAR(36), no flag
AWS SCT, RDS or Aurora target AWS asks you to set lower_case_table_names to 1. MySQL's manual says it "can only be configured when initializing the server" and changing it afterwards "is prohibited." Teams create the instance first and read the prerequisite second. On MySQL 8 the fix is a new instance, not a parameter change, which costs a day on a tight cutover. Parameter group before create
MySQL 8.4, default collation Server default is utf8mb4 with utf8mb4_0900_ai_ci, accent and case insensitive. A US-English SQL Server installs SQL_Latin1_General_CP1_CI_AS, which is case insensitive and accent sensitive. José and Jose were two customers in SQL Server and are one value in MySQL. The unique index fails to build with a duplicate-entry error, or the load drops one of them. Pick a collation per unique column
MySQL 8.4, trailing spaces Collations based on UCA 9.0.0 and later are NO PAD, so trailing spaces are significant. Microsoft says SQL Server treats 'abc' and 'abc ' as equivalent for most comparisons. Codes stored with a trailing space still load. The WHERE clause the application has used for ten years stops matching them, and it returns an empty result, not an error. RTRIM on load, or a PAD SPACE collation

The first row is the one to take away. SQL Server's TIMESTAMP is not a point in time, and Microsoft has said so for years: it is a synonym for rowversion, an incrementing 8-byte number used to detect that someone else changed a row since you read it. A mapping that matches on the type's name rather than its meaning produces a MySQL column that cannot hold the value, and an application whose conflict detection has quietly stopped working. If the goal is to keep MySQL current from SQL Server rather than move once, the capture options are compared in change data capture tools.

SQL Server types in MySQL, and the wrong target a default picks

A SQL Server to MySQL converter is mostly a type converter, and most of its choices are fine. INT, BIGINT, SMALLINT, DATE, TIME, FLOAT and DECIMAL with a declared precision cross cleanly. These twelve are the ones where the obvious choice is wrong, and most of them produce no error at load time.

SQL Server type Right MySQL target Common wrong target
BIT TINYINT(1) or BOOLEAN BIT(1), which returns bytes to many drivers
TINYINT TINYINT UNSIGNED Signed TINYINT, which stops at 127
MONEY, SMALLMONEY DECIMAL(19,4), DECIMAL(10,4) Bare DECIMAL, which is DECIMAL(10,0)
DATETIME DATETIME(3) DATETIME, which drops the milliseconds
DATETIME2(7) DATETIME(6) DATETIME, or TIMESTAMP, which ends in 2038
DATETIMEOFFSET DATETIME(6) in UTC plus an offset column DATETIME with the offset dropped
TIMESTAMP, ROWVERSION BINARY(8), or drop MySQL TIMESTAMP, a date type
UNIQUEIDENTIFIER BINARY(16) or CHAR(36) VARCHAR(64) with a unique flag on a foreign key
NVARCHAR(n) VARCHAR(n) in utf8mb4 Wide VARCHARs that break the 65,535-byte row
NVARCHAR(MAX), VARCHAR(MAX) LONGTEXT or MEDIUMTEXT VARCHAR(16383), which still counts toward the row
XML LONGTEXT, or JSON after conversion TEXT, which caps at 64 KB
SQL_VARIANT, HIERARCHYID A redesign, per column Nothing. Workbench lists both as not migrated

Two MySQL limits catch teams on shape rather than values. A MySQL row, not counting TEXT and BLOB stored off page, is capped at 65,535 bytes, and in utf8mb4 every VARCHAR character is budgeted at up to four bytes. A SQL Server table with five NVARCHAR(4000) columns is legal there and fails in MySQL with error 1118, "Row size too large". Names are the second limit: SQL Server allows 128 characters and MySQL allows 64, so a generated constraint name on a long table name can fail too. The full per-type walkthrough, with the one-line query that proves each mapping safe before the load, is in our guide to converting SQL Server data types to MySQL.

SQL Server to MySQL migration tools and converters compared

Billing units rather than price tags, except where the vendor publishes the number itself, as with Fivetran's $5 base charge per connection. Everything else is quoted, metered in ways that depend on your data, or has no license fee. Where a tool is wrong for a job, the last column says so, including for us.

Tool Approach Best for Billing unit What to watch
AWS SCT Schema and T-SQL conversion with an assessment report Planning a move to RDS or Aurora MySQL No charge for the tool itself Emulation schema; lower_case_table_names first
AWS DMS Full load plus ongoing replication One-time moves inside AWS with a cutover date Replication instance hours or serverless capacity No secondary indexes, defaults, procs or views
MySQL Workbench Migration Wizard over ODBC, schema plus data copy Small databases and one-off moves Community edition under the GPL Published type map, rows 1 to 5 above
SQLines Converts DDL, queries and T-SQL procedures Stored-procedure heavy schemas Licensed tools, quoted Code conversion, not an ongoing sync
Ispirer Automated conversion of schema, data and code Large estates with a services budget Quoted per project Scope and review time drive the price
DBConvert, dbForge Desktop copy and sync between two databases A single DBA, a single database Per-seat license Runs on a workstation, no audit trail
Airbyte SQL Server source with CDC to a MySQL destination Teams who want open source they can patch Self-hosted open source, credits on cloud Needs local_infile on MySQL
Fivetran Managed SQL Server connector to MySQL Teams already on Fivetran Monthly active rows, plus $5 base per connection MySQL destination is in Beta
Debezium plus JDBC sink SQL Server CDC to Kafka to MySQL Organizations already on Kafka Infrastructure and engineering time CDC must be enabled per table
Adapters Declared column mapping, incremental sync, per-record logs Typed MySQL tables fed from SQL Server on a flat bill Flat monthly from $49, not metered by rows Does not convert stored procedures

One name is missing on purpose. SQL Server Migration Assistant for MySQL is the tool many teams find first, because it comes from Microsoft and has both product names in its title. It moves MySQL into SQL Server and Azure SQL, which is the opposite direction to this page. For what a cutover of this size costs once the tool is chosen, see what a data migration really costs, and for the reverse of a common pairing, the MySQL to PostgreSQL migration tools page covers the same converter-default problem one engine over.

Six numbers to know before you sign anything

7 vs 6

Fractional-second digits in a default SQL Server datetime2 against the maximum a MySQL DATETIME can hold. The last digit always rounds.

Microsoft Learn and MySQL 8.4 manual, read 30 Sep 2026

(10,0)

What MySQL makes of a DECIMAL declared with no precision or scale. A MONEY column mapped to bare DECIMAL has no cents.

MySQL 8.4 manual, read 30 Sep 2026

65,535

Bytes in a MySQL row, not counting TEXT and BLOB. In utf8mb4 a VARCHAR character can take four of them, so a handful of NVARCHAR(4000) columns fails with error 1118.

MySQL 8.4 manual, read 30 Sep 2026

64

Characters in a MySQL table, column, index or constraint name. SQL Server allows 128, so long names break the DDL.

MySQL 8.4 manual, read 30 Sep 2026

Once

How often you can set lower_case_table_names: when the server is initialized. AWS SCT needs it set to 1 on RDS and Aurora.

MySQL 8.4 manual and AWS SCT guide, read 30 Sep 2026

_ai_ci

The suffix on MySQL 8.4's default collation: accent and case insensitive. SQL Server's US default is accent sensitive.

MySQL 8.4 manual and Microsoft Learn, read 30 Sep 2026

Eight ways this migration goes wrong while every check stays green

Both engines are relational and both enforce types, so teams expect a clean move. The problems are in the places the two disagree about meaning, where each value is legal on both sides and simply means something different after it lands.

The failure What you see What is actually happening
Cents rounded away Row counts match on every table MONEY landed in DECIMAL(10,0). Only a SUM comparison per column shows it.
Year-end revenue moves Daily totals match except on a few boundaries datetime2 rounded to the second, and a value at 23:59:59.6 became the next day, month or year.
Hours shift by region Every row present, every timestamp plausible DATETIMEOFFSET lost its offset, so local times from different zones are compared as one.
Concurrency check gone Updates succeed that should have been refused The rowversion column no longer increments, so two users can both save over each other.
Customers merged One missing row per accented duplicate utf8mb4_0900_ai_ci treats José and Jose as equal, and INSERT IGNORE dropped the second one.
Lookups return nothing Empty results, no error NO PAD collation made trailing spaces significant, so stored codes no longer match queries.
NULLs double up More rows with a NULL key than SQL Server allowed SQL Server lets a UNIQUE column hold one NULL. MySQL allows many, so the rule silently widened.
IDs collide after cutover First insert fails on the primary key AUTO_INCREMENT was not set above the loaded maximum, and a per-table IDENTITY step has no MySQL equivalent.

Six of the eight are fixed in the DDL or the server settings before the first row moves. The other two need a reconciliation after the load and a counter reset at cutover. If MySQL is a stop on the way to a warehouse, the same analysis for the warehouse leg is on SQL Server to Snowflake migration tools.

Six steps that decide whether this migration works

Step 1

Inventory the risky types on SQL Server

One query against sys.columns lists every rowversion, datetimeoffset, money, uniqueidentifier, sql_variant and hierarchyid column in the database. That list is the real scope of the project, and it is usually shorter than people fear.

Step 2

Decide the MySQL server settings first

Character set, default collation and lower_case_table_names have to be right before the instance holds data. On RDS and Aurora that means a parameter group attached at creation, not afterwards.

Step 3

Write or correct the DDL by hand

Let SCT or Workbench generate a draft, then fix the types on this page: DATETIME(6), DECIMAL(19,4), BINARY(16), BINARY(8). A tool that creates tables at load time creates them with its defaults.

Step 4

Check the row width of every table

Sum the declared widths at four bytes per character. Any table above 65,535 bytes needs its longest strings moved to TEXT before the CREATE TABLE will run.

Step 5

Full load, then change capture to cutover

Load history once, then follow SQL Server CDC or Change Tracking until the switch, so the cutover takes minutes. CDC has to be enabled per database and per table, which is a DBA ticket to raise early.

Step 6

Reconcile values, then reset the counters

Compare SUM on every numeric column, MIN and MAX on every date and daily totals around midnight UTC. Then set each AUTO_INCREMENT above its loaded maximum and insert one test row per table.

Step five is where a subscription earns its keep or does not. If the move is one weekend, DMS or Workbench does it and you are done. If SQL Server stays live for months while the application is rewritten, you need the same mapping running every few minutes with a log of every record, which is what a flat Adapters plan covers without counting rows.

Why US teams fund this project

Cutting SQL Server licensing

The most common reason we hear. Per-core licensing for an application database that uses no SQL Server-specific features is a line item finance keeps asking about, and MySQL on RDS or Aurora removes it.

Consolidating on a MySQL stack

A company that acquired a .NET product and runs everything else on MySQL wants one engine to back up, patch, monitor and hire for.

Feeding a MySQL-based product

An ERP or line-of-business system stays on SQL Server while a customer portal built on MySQL needs its orders, invoices and accounts every few minutes.

Moving to Aurora MySQL

Teams already on AWS moving a SQL Server workload into a managed MySQL-compatible engine, usually with SCT for the schema and something else for the ongoing data.

Retiring a Windows server

An on-premises SQL Server Express or Standard box under a desk is the last Windows machine in the estate, and the application behind it is simple enough to move.

Running both during a long cutover

The migration takes a quarter, not a weekend, so SQL Server stays the system of record while MySQL is kept current and checked against it until the switch.

Five jobs where you should not pick us

A comparison page that never says the competition wins is an advert. These are the cases where something else on this page is the right answer.

  • This is a one-time move inside AWS with a fixed cutover date. SCT for the schema and DMS for the data is the documented path, it bills by the hour, and a subscription adds nothing once the switch is done.
  • Your database is mostly stored procedures, functions and triggers. That is a code conversion project. SQLines, Ispirer or AWS SCT with its extension pack are built for T-SQL, and we do not convert procedural code at all.
  • The database is small and the move happens once. The MySQL Workbench Migration Wizard will do it with no license fee, provided you correct the five type mappings in the table above before you press run.
  • You already run Kafka and Debezium. Enabling SQL Server CDC and adding a JDBC sink covers this route, and a vendor adds little to a pipeline your team already operates.
  • You need sub-second latency from a SQL Server commit to a MySQL row. Streaming platforms built for that job will beat our scheduled sync.

Four questions to ask any vendor on this list

Question 01

Can I see the DDL before anything loads?

Ask for the generated CREATE TABLE statements for your five riskiest tables and read the types yourself. If the answer is that the tool creates tables automatically at load time, you are accepting its defaults, and this page lists what those are.

Question 02

What happens to rowversion and datetimeoffset?

Two questions that sort vendors quickly. A good answer names BINARY(8) or a deliberate drop for the first, and a UTC conversion with a stored offset for the second. A vague answer means the vendor has not met either type.

Question 03

How do you reconcile, and on what?

Row counts are the wrong answer. Ask whether the tool compares sums, date ranges and key hashes per table, and whether it keeps a per-record log you can show an auditor when a number is questioned.

Question 04

What does it cost when volume doubles?

Rows, events, credits and instance hours all grow with data. Ask for the bill at twice your current volume and during the month of the initial full load, which is often the most expensive month of the contract.

Questions buyers ask about SQL Server to MySQL migration

How do I migrate from SQL Server to MySQL?
Convert the schema first with a tool that shows you its type choices, then fix the DDL by hand before any data moves: DATETIME(6) for datetime2, DECIMAL(19,4) for money, BINARY(8) or nothing for rowversion, and a collation decision for every unique text column. Then run a full load, follow changes until cutover, and reconcile on values rather than row counts.
What is the best SQL Server to MySQL migration tool?
It depends on what you are moving. AWS SCT plus DMS is the standard pairing for a one-time move into RDS or Aurora MySQL. MySQL Workbench's Migration Wizard handles a small database with no license fee. SQLines and Ispirer convert T-SQL procedures. For an ongoing sync into typed MySQL tables, use a tool that lets you declare the target columns.
Can MySQL Workbench migrate SQL Server to MySQL?
Yes. The Migration Wizard in MySQL Workbench lists Microsoft SQL Server as a supported source and connects over ODBC. Read its published type mapping before you run it. The manual maps SQL Server TIMESTAMP and ROWVERSION to a MySQL TIMESTAMP, DATETIMEOFFSET to DATETIME, and MONEY to DECIMAL, and all three change your data without an error.
Does SQL Server Migration Assistant support SQL Server to MySQL?
No. SQL Server Migration Assistant for MySQL, often called SSMA or MySQLToSQL, moves databases from MySQL into SQL Server and Azure SQL. That is the opposite direction. For SQL Server to MySQL use AWS SCT, the MySQL Workbench Migration Wizard, a commercial converter such as SQLines or Ispirer, or a sync tool.
What is the MySQL equivalent of SQL Server timestamp?
There is none, because SQL Server timestamp is not a date. Microsoft documents it as a synonym for rowversion, an 8-byte incrementing number that "does not preserve a date or a time." Map it to BINARY(8) if the application uses it for optimistic concurrency, or drop it and use a DATETIME(6) updated_at column. Never map it to MySQL TIMESTAMP.
What is the MySQL equivalent of datetime2?
DATETIME(6). SQL Server datetime2 defaults to 7 fractional digits, an accuracy of 100 nanoseconds, while MySQL stops at 6. The seventh digit is rounded, which can push 23:59:59.9999995 into the next day. A DATETIME declared with no precision has zero fractional digits, so every value rounds to the nearest second.
What is the MySQL equivalent of uniqueidentifier?
BINARY(16) if you care about index size, or CHAR(36) if people read the values directly. The MySQL Workbench mapping uses VARCHAR(64) and notes that a unique flag is set in MySQL. Check that flag against each column: a GUID foreign key legitimately repeats, and a unique index on it would reject valid rows.
How do I convert SQL Server MONEY to MySQL?
Declare DECIMAL(19,4). SQL Server MONEY keeps four decimal places, and MySQL's manual says a DECIMAL declared without precision or scale is DECIMAL(10,0), which has no decimal places at all. If a generated DDL script shows a bare DECIMAL, every cent is rounded away while row counts still match perfectly.
Does AWS DMS support SQL Server to MySQL?
Yes. DMS supports SQL Server as a source and MySQL, RDS for MySQL and Aurora MySQL as targets, with a full load plus ongoing replication. AWS states that DMS does not migrate secondary indexes, default values, stored procedures, triggers or views, so it is normally paired with AWS SCT for the schema.
Why do my MySQL queries miss rows after migrating from SQL Server?
Usually trailing spaces. SQL Server pads strings before comparing them, so it treats 'VAT-01' and 'VAT-01 ' as equal. MySQL 8.4's default collation, utf8mb4_0900_ai_ci, is NO PAD, so trailing spaces count. A lookup that matched in SQL Server returns nothing in MySQL, with no error. Trim the values or choose a PAD SPACE collation.

For the wider vendor landscape see the best data integration tools, and for the type-by-type checks to run before the first load, read how to convert SQL Server data types to MySQL.

Keep MySQL in step with SQL Server until the day you switch

Declare the columns once with DATETIME(6), DECIMAL(19,4) and BINARY(16) where they belong, run the backfill, then let the same mapping sync incrementally with retries and per-record logs. From $49 a month, not metered by rows.

The live demo needs no card, and Starter is $49 a month.

Get started