Migrating from MySQL to MariaDB: Dump, Restore, and the Compatibility Gaps

6 min readMySQL

Migrating from MySQL to MariaDB

MySQL 8.0 reached end of life on April 30, 2026, and Oracle's licensing terms around MySQL Enterprise features push some compliance reviews toward a fully GPL alternative. That combination is why this migration question keeps coming up. This guide covers the mechanics: why you can't do it in place anymore, the dump/restore workflow that works, and the four areas where MySQL and MariaDB have genuinely diverged.

First, the honest framing: MariaDB stopped being a drop-in replacement for MySQL years ago. The fork happened at MySQL 5.5 in 2009, and both projects have since added incompatible features — different GTID formats, different JSON internals, different default authentication. For most applications the move is still straightforward, but "straightforward" is not "automatic." And if your only concern is the 8.0 EOL, note that upgrading to MySQL 8.4 LTS (supported until 2032) is less work than switching engines. Migrate because you want something MariaDB specifically offers — the GPL licensing story, the built-in thread pool, Galera clustering, system-versioned tables — not because the EOL forced your hand.

Version Targets

Coming from MySQL 8.0 or 8.4, MariaDB's own migration guide recommends MariaDB 11.8 LTS or 12.3 LTS (as of July 2026, the two current long-term series). Older targets like 10.11 are fine coming from MySQL 5.7 but lack the MySQL-8-era compatibility work — most importantly the utf8mb4_0900_* collation aliases discussed below, which arrived in 11.4.5.

Why In-Place Doesn't Work Anymore

Migrating from MySQL 5.7 and earlier, you could historically stop MySQL, install MariaDB over the same data directory, and run the upgrade script. That path is gone for MySQL 8.0 and later. MySQL 8.0 replaced the FRM-file metadata system with a transactional data dictionary stored inside InnoDB — a format MariaDB never adopted and cannot read. Point a MariaDB server at a MySQL 8.x data directory and it will fail to start.

The supported route from 8.0/8.4 is a logical dump and restore. Plan downtime (or a replication-based cutover, covered below) accordingly.

The Dump

Two details matter more than everything else:

Use mysqldump, not mariadb-dump, for the export. MariaDB's dump tool isn't extensively tested against MySQL servers.

Never dump --all-databases. That includes the mysql system schema, and MySQL's system tables (users, privileges, the data dictionary views) are structured differently from MariaDB's. Loading them into MariaDB fails or, worse, half-succeeds. Name your application databases explicitly:

mysqldump --user=root --password --databases app1 app2 \
  --single-transaction --routines --events \
  --triggers --hex-blob > migration_dump.sql

--single-transaction gives a consistent InnoDB snapshot without locking, --routines --events --triggers bring your stored code, and --hex-blob avoids binary-data corruption in transit.

Users and grants need separate handling: script them out with SHOW CREATE USER / SHOW GRANTS statements and replay them on MariaDB, adjusting authentication plugins as described next.

The Four Real Compatibility Gaps

1. Authentication plugins

MySQL 8.0 defaults to caching_sha2_password, and MySQL 8.4 disables the old mysql_native_password plugin by default. MariaDB does not implement caching_sha2_password at all — its defaults are mysql_native_password and unix_socket, with ed25519 as the modern strong option. Every account you carry over needs its authentication reset on the MariaDB side:

ALTER USER 'app'@'%' IDENTIFIED VIA mysql_native_password USING PASSWORD('...');
-- or, stronger:
ALTER USER 'app'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('...');

Check your client drivers too: ed25519 is not implemented by every connector (several scripting-language drivers lack it), so test a real application login before cutover.

2. The utf8mb4_0900_ai_ci collation trap

MySQL 8.0's default collation is utf8mb4_0900_ai_ci. For years, importing a MySQL 8 dump into MariaDB died with Unknown collation: 'utf8mb4_0900_ai_ci' — the single most common failure in this migration. MariaDB 11.4.5 (February 2025) fixed this by adding utf8mb4_0900_* as aliases for its UCA-14.0.0 collations, precisely to ease MySQL migration and replication (MDEV-20912, MDEV-35256).

Target 11.8 or 12.3 and the dump loads as-is. On anything older, rewrite the collation in the dump first:

sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_520_ci/g' migration_dump.sql

Be aware the alias maps to a UCA-14.0.0 implementation, not a byte-identical reimplementation of MySQL's collation — sort order matches for common cases, but if your application depends on exact collation-weight behavior (unusual), test it.

3. GTIDs and replication

MySQL and MariaDB use entirely different GTID formats — MySQL's server_uuid:transaction_id sets versus MariaDB's DomainID-ServerID-Sequence. They do not interoperate. If you want a minimal-downtime cutover, you can attach a MariaDB replica to a MySQL primary using binlog position-based replication (the 0900 collation aliases exist partly to make this work), let it catch up, then promote it. Just don't attempt GTID-mode replication across the two, and treat the hybrid setup as temporary — it's a migration bridge, not a topology.

4. JSON internals

MySQL stores JSON in a native binary format; MariaDB's JSON type is an alias for LONGTEXT with a validity CHECK constraint. The SQL-level function set (JSON_EXTRACT, JSON_TABLE, and friends) is highly compatible, so most code just works — but storage size and extraction performance differ. mysqldump exports JSON as text, so the data itself moves cleanly. If you have hot paths doing heavy JSON attribute extraction, benchmark them on MariaDB before committing.

Restore and Verify

mariadb --user=root --password < migration_dump.sql

Then validate with checksum queries against both servers — same query, both engines, diff the output:

SELECT COUNT(*), SUM(CRC32(CONCAT_WS('#', id, email, updated_at)))
FROM app1.users;

Run MIN()/MAX() on date columns and row counts per table. Since MariaDB speaks the MySQL wire protocol, any client that connects to one connects to the other — Mako, for instance, can hold connections to the old MySQL server and the new MariaDB server side-by-side and run the identical query against each, which makes the verification loop fast.

Common Mistakes

MistakeConsequenceFix
Pointing MariaDB at a MySQL 8.x data directoryServer won't startLogical dump/restore; in-place is 5.7-era only
Dumping --all-databasesSystem-schema import failures--databases app1 app2 ... explicitly
Ignoring authentication pluginsApps can't log in after cutoverRecreate accounts with mysql_native_password or ed25519; test drivers
Old MariaDB target + 0900 collationsUnknown collation import failureTarget 11.4.5+/11.8/12.3, or sed the dump
Trying GTID replication MySQL↔MariaDBReplication refuses or breaksPosition-based replication for the bridge
Migrating with no MariaDB-specific reasonEffort spent, nothing gainedMySQL 8.4 LTS is supported to 2032 — upgrading is less work

For the underlying feature comparison, see MySQL vs MariaDB. If your application code is next, the connection layer rarely changes — see connecting to MariaDB from Python and the rest of the connect-from series for driver-level differences like ed25519 support.

Mako connects to both MySQL and MariaDB with AI-powered autocomplete — useful for running the same validation queries against both servers during cutover. Try it free at mako.ai.

Mako — open source

Skip the terminal. Use Mako.

Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.