Migrate SQL Server to MySQL
Beta — live-tested pathMigrating from SQL Server (Microsoft's enterprise relational database) to MySQL (the world's most deployed open-source relational database) means every table, column type, key, index and row has to survive two engines' different opinions about data. DBShifts converts the schema with deterministic rules, transfers data in parallel batches, and validates the result with per-table row counts and type-aware checksums.
Free tier · no credit card
SQL Server vs MySQL
SQL Server
Microsoft's enterprise relational database.
MySQL
the world's most deployed open-source relational database.
How the migration works
Connect
Point DBShifts at your source and target. Credentials stay encrypted; SSH tunnels supported for private databases.
Analyze
Automatic schema introspection produces a migration plan: what converts automatically, what migrates with warnings, what needs human review.
Migrate
Schema is created on the target, data transfers in parallel batches with constraints deferred, indexes rebuilt after load.
Validate
Per-table row counts, type-aware checksums on both sides, FK integrity — plus a fidelity report listing anything lossy.
SQL Server to MySQL data type mapping
Pulled directly from DBShifts's own conversion rules — not a general reference table, this is what actually runs.
| SQL Server | MySQL |
|---|---|
| INT | int |
| BIGINT | bigint |
| SMALLINT | smallint |
| TINYINT | tinyint unsigned |
| BIT | tinyint(1) |
| DECIMAL(10,2) | decimal(10,2) |
| MONEY | decimal |
| FLOAT | double |
| REAL | float |
| VARCHAR(255) | varchar(255) |
| NVARCHAR(255) | varchar(255) |
| NVARCHAR(MAX) | LONGTEXT |
| TEXT | text |
| CHAR(10) | char(10) |
| DATE | date |
| DATETIME | datetime |
| DATETIME2 | datetime |
| DATETIMEOFFSET | timestamp |
| TIME | time |
| VARBINARY(MAX) | blob |
| UNIQUEIDENTIFIER | CHAR(36) |
Example: SQL Server to MySQL schema conversion
SQL Server
CREATE TABLE orders ( id INT IDENTITY(1,1) PRIMARY KEY, customer_id INT NOT NULL, total DECIMAL(10,2) NOT NULL, is_gift BIT NOT NULL DEFAULT 0, notes NVARCHAR(MAX), reference UNIQUEIDENTIFIER, placed_at DATETIME2 NOT NULL );
MySQL
CREATE TABLE IF NOT EXISTS `orders` (
`id` int NOT NULL,
`customer_id` int NOT NULL,
`total` decimal(10,2) NOT NULL,
`is_gift` tinyint(1),
`notes` LONGTEXT,
`reference` CHAR(36),
`placed_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;Schemas do not survive, because MySQL does not have them
In SQL Server, dbo.orders and archive.orders are two tables in one database. In MySQL, a database is the namespace — there is no second level. Both tables want to be called orders, and one of them has to change.
There are two honest options. Flatten with a prefix, so archive.orders becomes archive_orders, which keeps everything in one database and breaks every query that referenced the schema. Or map each SQL Server schema to its own MySQL database, which preserves the two-part name but means cross-schema joins become cross-database joins, and a single transaction spanning them behaves differently.
Pick before converting. This decision propagates into every stored query, every ORM mapping and every report, and reversing it later is a second migration.
InnoDB's index key limit will reject indexes SQL Server allowed
InnoDB caps an index key at 3072 bytes. Under utf8mb4, MySQL reserves four bytes per character, so an index on a VARCHAR(1000) is computed as 4000 bytes and refused with error 1071 — even though no actual row is near that. SQL Server's 1700-byte limit on a nonclustered key is measured differently and lets the same column through.
The practical effect is that wide text indexes, and composite indexes over several medium text columns, do not convert one-to-one. A prefix index on the first N characters usually restores the lookup performance, but it is a different index with different uniqueness properties, so a unique constraint cannot be prefixed away without changing what the database enforces.
Datetime precision and the IDENTITY column
DATETIME2(7) carries 100-nanosecond precision. MySQL's DATETIME tops out at six fractional digits, so the seventh is dropped. That is usually irrelevant and occasionally not: if timestamps are used as a tiebreaker or an ordering key, two rows that were distinct in SQL Server can become equal in MySQL.
IDENTITY becomes AUTO_INCREMENT, with one structural constraint that catches people out — MySQL permits exactly one AUTO_INCREMENT column per table and it must be indexed. A SQL Server table with an IDENTITY column that is not part of the primary key needs that index adding. After the load, the counter has to be reseeded above the highest imported value, or the first production insert collides.
SQL Server → MySQL conversion notes
Engine-specific rules baked into the conversion and transfer pipeline — verified by live certification of this exact pair.
- TINYINT is unsigned (0–255) in SQL Server — DBShifts widens it on signed targets so 128–255 don't clip.
- UNIQUEIDENTIFIER, DATETIMEOFFSET, MONEY and NVARCHAR(MAX) all have explicit conversion rules per target.
- Wrapped defaults like ((1)) and (N'foo') are unwrapped to portable literals.
- AUTO_INCREMENT counters are reseeded to MAX(id)+1 after bulk load, so the first production insert doesn't collide.
- Oversized VARCHAR definitions from other engines are rewritten to TEXT/LONGTEXT to respect MySQL's row-size limits.
- Foreign keys are applied after data load with FOREIGN_KEY_CHECKS deferred for speed and ordering safety.
Frequently asked questions
Is SQL Server to MySQL migration production-ready in DBShifts?
SQL Server to MySQL is a live-verified beta pair: it passed the same certification suite as every other pair — a real migration with edge-case data validated by row counts and checksums — and ships with a post-migration fidelity report you can audit before cutover.
How does DBShifts verify the SQL Server to MySQL migration was correct?
Three layers: per-table row counts on both sides, an order-independent type-aware checksum of row data (canonicalized so engine representation differences don't false-alarm), and FK integrity checks on the target. Rows that fail to insert are quarantined with the exact error — never silently dropped — and can be fixed and retried from the UI.
What happens to SQL Server types that MySQL doesn't have?
They convert by deterministic rules with a recorded decision: a native equivalent where one exists, a portable fallback (TEXT/JSON/DECIMAL) where one doesn't. Every lossy conversion appears in the migration plan before you run and in the fidelity report after. You can override any mapping per column.
Can I keep SQL Server and MySQL in sync after the initial migration?
Yes. DBShifts supports incremental sync (UPSERT-based delta transfers on a sync key) and, for supported sources, real-time change data capture so the target stays current until you cut over.
Do I need to write any SQL or scripts for SQL Server to MySQL?
No. Connect both databases, review the generated migration plan (what's automatic, what migrates with warnings, what needs manual review — typically triggers and stored procedures), and run. Procedural code is transpiled best-effort and queued for human review rather than auto-applied.
What's the hardest part of moving SQL Server to MySQL?
Type-system mismatches that fail silently rather than loudly — SQL Server's edge-case types (3 engine-specific rules apply) converting into MySQL's nearest equivalent. DBShifts's deterministic mapping records every downgrade in the fidelity report, so a value that clips, rounds, or widens is visible before cutover, not after.
Which SQL Server data types change when moving to MySQL?
5 of the mapped types convert to something that cannot represent exactly the same range or constraint. The clearest cases are MONEY to decimal, FLOAT to double, DATETIMEOFFSET to timestamp. The full table above lists every mapping the converter performs, and analysis flags each one on your actual schema before any data moves.
Go deeper
Related migration paths
Ready to move SQL Server to MySQL?
Set up in under two minutes. Validation and rollback included.
Start Free Migration