Skip to content
IntoSQL home

Migration guides

MySQL to MariaDB migration guide

Convert a MySQL dump into a MariaDB script that loads on the first try: what MariaDB doesn't accept, how to load it, and every rule the converter applies.

View as Markdown

IntoSQL reads a MySQL or MariaDB dump and writes one MariaDB script with the same tables, columns, keys, indexes, foreign keys, defaults, counters and rows. A MySQL 8 dump often fails on MariaDB as it is (the utf8mb4_0900_ai_ci collation, functional defaults, invisible columns); the converter rewrites what MariaDB doesn't accept and lists every change in the report. The script loads on MariaDB 10.11 and later.

Convert in the browser: MySQL to MariaDB opens the converter set up for this pair.

Dump for the best result

Any dump from mysqldump, mariadb-dump, mysqlpump, phpMyAdmin or Adminer works, as .sql or .sql.gz. These options keep more of your data:

Terminal
mysqldump --default-character-set=utf8mb4 --hex-blob \
  --routines --triggers --events --single-transaction \
  shop | gzip > shop.sql.gz
  • --default-character-set=utf8mb4 keeps emoji and other 4-byte characters. A dump made with utf8 has already lost them, and the report says so (dump_lost_four_byte_chars).
  • --hex-blob writes binary columns as hexadecimal, which survives copying between systems.
  • --routines --triggers --events add those objects to the dump, so the report can list them by name.
  • --single-transaction takes a consistent snapshot of InnoDB tables without locking them.

A dump made with --no-create-info still converts: the types are read from the values, and the report says the schema was missing (no_schema).

Convert

In the browser, open MySQL to MariaDB or the converter on the home page, drop the dump and choose MariaDB. It reads the file from your disk in pieces, twice, and writes the script as it goes, so the dump is never uploaded and its size isn't limited by memory. The desktop app does the same with the file on disk.

With the command line:

Terminal
intosql inspect shop.sql.gz
intosql convert shop.sql.gz --to mariadb --output shop.mariadb.sql --report shop.report.json

inspect lists the tables, their rows and what won't be converted, without writing anything. convert writes the script and, with --report, the report as JSON.

Through the API, a dump converts like any other file: open a conversion with its name ending in .sql or .sql.gz and "output": {"dialect": "mariadb"}.

Load into MariaDB

Terminal
mariadb -e "CREATE DATABASE shop"
mariadb --default-character-set=utf8mb4 shop < shop.mariadb.sql

The script sets the character set, the time zone and a SQL mode that accepts the dump's zero and impossible dates, then creates each table with its keys and copies the rows with foreign key and unique checks off, as mysqldump does. Each AUTO_INCREMENT counter continues where the dump left it.

Or load it straight in

intosql load and the desktop app load the dump into MariaDB without a script, with the same tables, keys and indexes the script creates:

Terminal
intosql load shop.sql.gz --into mariadb://ana@localhost/shop

It stops before writing anything when one of the dump's tables already exists. MariaDB can't roll back a table, so a failed load drops the tables it created. Loading into a database server is part of IntoSQL Pro, with a 14-day trial. See Loading.

What isn't converted

Views, triggers, stored procedures, functions and events are listed in the report by kind and name, never dropped silently, so you can check each one against MariaDB before recreating it. ON UPDATE CURRENT_TIMESTAMP stays as it is.

Data types

MySQL to MariaDB data types lists each type that changes in the script: what it becomes, why, and the report line.

Every other rule

Generated from the engine, where each rule is decided.

In MySQL In MariaDB Why Report line
utf8mb4_0900_* and utf8mb4_uca1400_* collations utf8mb4_unicode_520_ci for utf8mb4_0900_* (utf8mb4_bin for binary ones) MariaDB doesn't know the newer collations, the error that stops most MySQL 8 dumps from loading elsewhere. unicode_520 follows the same Unicode rules most closely. collation_replaced
ON UPDATE CURRENT_TIMESTAMP kept The same clause, with the column's fractions of a second. None
generated columns VIRTUAL or STORED as in the source The same formula, translated term by term. None
generated columns with functions IntoSQL doesn't read a plain column A formula IntoSQL can't read leaves a plain column and a report line. generated_not_translated
INVISIBLE columns INVISIBLE columns MySQL has invisible columns from 8.0.23, MariaDB from 10.3. None
CHECK constraints kept The same checks, translated term by term. None
CHECK constraints with functions IntoSQL doesn't read not created A check IntoSQL can't read is left out and reported. check_skipped
CHECK ... NOT ENFORCED not created MySQL 5.7 and MariaDB can't keep a check without applying it, and the rows may break it. check_not_enforced
expression defaults, and defaults on TEXT, BLOB, JSON and GEOMETRY kept MySQL takes them from 8.0.13; the script loads on 5.7, so they are left out and reported. MariaDB takes them. default_not_translated
functional indexes, KEY ((expr)) not created MySQL indexes expressions from 8.0.13 and MariaDB not at all; a generated column with an index does the same. index_skipped
keys and indexes on a prefix, c(20) kept The same index. None
FULLTEXT indexes kept The same index; MATCH ... AGAINST works as before. None
SPATIAL indexes kept The same index. None
foreign keys kept, loaded with FOREIGN_KEY_CHECKS=0 The same keys; rows load as they did from the source dump. None
PARTITION BY one table The rows are the same; partition the table again if it needs it. partitions_dropped
WITH SYSTEM VERSIONING (MariaDB) WITH SYSTEM VERSIONING, starting from the current rows A dump holds the current rows only; MySQL has no system versioning. None
Aria, ColumnStore, CONNECT, Spider, RocksDB (MariaDB) kept MySQL has none of these engines. Every other engine is kept. None
CREATE SEQUENCE (MariaDB) CREATE SEQUENCE with its next value MySQL has no sequences. None
views, triggers, procedures, functions and events listed in the report They are listed for you to recreate; their code often names its definer and server features. not_converted_objects
NOT NULL columns with values that become NULL NOT NULL dropped A column whose values had to become NULL can't keep NOT NULL, or the load would stop. not_null_relaxed
text decoded twice (ñ) copied as it is The dump holds exactly these characters, so they are copied; the report points them out. mojibake_suspected
dumps without CREATE TABLE types read from the values A dump made with --no-create-info only has rows, so the types come from the values. no_schema
SET NAMES utf8 from utf8mb4 tables converted, with a warning MySQL 5.x mysqldump writes 3-byte utf8 by default and replaces every emoji with a question mark before any converter sees the file. dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8 read as Latin-1 (Windows-1252) MySQL's latin1 is Windows-1252, the usual encoding of such dumps. charset_guessed
sjis, cp932, gbk, big5 dumps read as UTF-8, with a warning These encodings are not decoded yet. unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows evaluated Some dump tools write values as these calls; they are read as the values they produce. None
other expressions in rows NULL A converter that doesn't run a database can't evaluate them. expression_value
DEFAULT in VALUES the column's default value A literal default is copied into the row. default_keyword_filled
DEFAULT in VALUES without a literal default NULL There is no value to copy. default_keyword_null
REPLACE and INSERT IGNORE plain rows A dump has one row per key, so the rows are the same. replace_as_insert