Chapter 02 · MariaDB vs MySQL: Compatibility, Divergence, and Migration Awareness
Version Numbering, Removed/Added Features, Defaults, and Configuration Divergence
Compare MariaDB and MySQL release numbering, configuration surfaces, defaults, utility names, and product-specific capabilities without mapping independent version numbers or copying MySQL administration blindly.
Learning outcomes
A migration ticket says “source: MySQL 8; target: MariaDB 12.”
Someone infers that MariaDB 12 must be several major generations
newer than MySQL 8 and therefore should support every MySQL 8
feature. Another engineer copies a MySQL
SET PERSIST command into the MariaDB runbook
because both servers expose system variables. Both mistakes come
from treating independent release numbers and similar
administrative vocabulary as if they shared one implementation
timeline.
This lesson teaches a version-and-configuration discipline. As reviewed on August 20, 2026, MariaDB Foundation lists Community Server 12.3.2 in the long-term release family, while 13.0.1 is an RC rolling release and 13.1 is preview. MySQL 8.4.11 is a current 8.4 LTS maintenance release, and MySQL also has a newer 9.7 LTS family. Those numbers are not coordinates on a shared scale. Always compare exact source and target versions, edition/package, feature, and configuration behavior.
Explain why MariaDB and MySQL version numbers must never be mapped by visual similarity.
Distinguish release-series selection from maintenance patching and development/preview maturity.
Identify configuration variables/options that are absent, renamed, or semantically different on the target.
Explain the MySQL SET PERSIST mechanism and why
it must not be copied into MariaDB.
Inventory MariaDB-specific capabilities and renamed utilities without assuming they exist in every package.
Mandatory examples target MariaDB Community 12.3.2. MySQL comparison examples use MySQL Community 8.4.11 LTS unless explicitly labeled otherwise. The academy’s planned MariaDB syllabus still mentions 11.8 LTS as a historical coverage anchor; version-sensitive statements are re-checked against current documentation instead of freezing that wording.
1. Release numbers belong to product-specific policies
A version number carries meaning only inside its product’s release policy. MariaDB has its own long-term and rolling/development progression. MySQL has its own LTS and Innovation tracks. The projects can add, deprecate, or remove features on different schedules. Therefore “MariaDB 12 versus MySQL 8” tells you almost nothing about which SQL, authentication, optimizer, or replication features overlap.
| Question | MariaDB evidence | MySQL evidence |
|---|---|---|
| What is stable now? | MariaDB Foundation release page and Community release notes | MySQL release notes/download track |
| Is this LTS or development? | MariaDB release family/maturity label | MySQL LTS or Innovation label |
| What changed in this patch? | Exact MariaDB maintenance release notes | Exact MySQL maintenance release notes |
| How long is it supported? | MariaDB lifecycle/engineering policy for product/series | Oracle MySQL support policy for series |
| Can I upgrade directly? | Target MariaDB upgrade path and compatibility docs | Target MySQL upgrade-path docs |
Use release notes as change-control input. A maintenance update may contain security fixes and behavior corrections even when the feature set is intended to remain stable. A migration between products is a larger change than either vendor’s ordinary maintenance update and therefore requires its own test matrix.
2. Configuration names are an API—and APIs diverge
Operations teams often have hundreds of lines of option-file settings. Treat those names and values as executable dependencies, not documentation. MariaDB and MySQL share many historical option names, but each also has variables that the other lacks or implements differently. Current MariaDB documentation publishes system-variable difference tables precisely because copying a configuration file is not a safe migration strategy.
SELECT VERSION(), @@version_comment;SHOW VARIABLES WHERE Variable_name IN ( 'sql_mode', 'character_set_server', 'collation_server', 'default_storage_engine', 'binlog_format', 'log_bin', 'max_connections');SHOW VARIABLES LIKE 'gtid%';SHOW VARIABLES LIKE 'wsrep%';SHOW VARIABLES LIKE 'persist%';SHOW VARIABLES LIKE 'thread_pool%';
The purpose is not to force both servers to expose identical rows. The difference is the result. Record existence, scope, current value, dynamic/restart behavior, persistence mechanism, and any edition/plugin prerequisites. When a variable is absent, decide whether the underlying capability moved, has a different name, is automatic, requires a plugin, or simply does not exist.
3. Concrete divergence: MySQL SET PERSIST versus MariaDB option-file persistence
MySQL 8.4 supports SET PERSIST and
SET PERSIST_ONLY for eligible global variables.
MySQL writes persisted values to mysqld-auto.cnf in
the data directory and can apply them on later startups. MariaDB
compatibility documentation explicitly lists MySQL’s
SET PERSIST as unsupported. MariaDB administrators
normally separate a runtime change such as
SET GLOBAL from persistent configuration in MariaDB
option files or package/service configuration.
-- This is MySQL administrative syntax, not a MariaDB persistence workflow.SET PERSIST max_connections = 250;
On a current MariaDB server, do not expect this to behave like
MySQL. The correct MariaDB exercise is safer: inspect
@@global.max_connections, make a temporary runtime
change only on a disposable server if you have the required
administrative privilege, then revert it. Persistent
configuration is taught in Chapter 03 using the actual
option-file discovery and precedence rules for the installed
package.
SELECT @@global.max_connections AS before_value;-- Administrative privilege required; choose a harmless disposable lab value.SET GLOBAL max_connections = 180;SELECT @@global.max_connections AS changed_value;SET GLOBAL max_connections = 151;SELECT @@global.max_connections AS restored_value;
The compiled/package default is version-sensitive. Before
changing anything, record the original value and restore
exactly that observed value. The sample 151 is
illustrative, not a universal MariaDB default.
4. Utility names and operational scripts also diverge
MariaDB renamed its client and server utilities to the
mariadb* family: mariadb,
mariadb-admin, mariadb-dump,
mariadb-binlog, mariadb-backup, and
others. Compatibility symlinks using historical
mysql* names can exist on some Unix-like packages,
but packaging can remove or omit aliases. A runbook that calls
mysqladmin or mysqldump without
verifying the executable provenance can silently invoke a
different vendor’s tool or fail after an OS/package upgrade.
mariadb --versionmariadb-admin --versionmariadb-dump --versionmariadb-binlog --version# If historical aliases exist, verify them rather than assuming:mysql --versionmysqldump --version
On Windows PowerShell, the same executable names can be invoked
directly after adding the MariaDB bin directory to
PATH, or by using their full paths. On Linux,
package managers and alternatives systems can influence which
binary a generic name resolves to. Record the executable path
and version in automation evidence.
5. Feature inventories should expose asymmetry, not create a winner
MariaDB has capabilities that are not direct MySQL equivalents, such as standalone sequence objects, system-versioned tables, Galera integration, and a broad pluggable storage-engine ecosystem including Aria. MySQL has its own capabilities and administrative mechanisms, including its persisted-system-variable workflow and product-specific Group Replication ecosystem. The migration question is not which list is longer; it is which capabilities your workload actually depends on.
SHOW ENGINES;SHOW PLUGINS;SHOW VARIABLES LIKE 'wsrep%';-- MariaDB sequence syntax (run only on MariaDB):DROP SEQUENCE IF EXISTS servicehub_compat.ticket_seq;CREATE SEQUENCE servicehub_compat.ticket_seq START WITH 1000 INCREMENT BY 1;SELECT NEXT VALUE FOR servicehub_compat.ticket_seq AS next_ticket_number;SHOW CREATE SEQUENCE servicehub_compat.ticket_seq;DROP SEQUENCE servicehub_compat.ticket_seq;
The sequence probe teaches two things. First, MariaDB exposes a
real sequence object and NEXT VALUE FOR. Second, a
feature can be perfectly valid MariaDB SQL yet be inappropriate
for a migration that must remain executable on MySQL.
Portability is a design requirement you choose; it is not a
property that automatically follows from using familiar syntax.
6. Defaults are invisible dependencies until they change
SQL mode, character set, collation, time zone, binary-log
format, authentication defaults, and storage-engine defaults can
influence application behavior without appearing in table DDL.
This is why the Chapter 01 lab recorded explicit
utf8mb4, InnoDB, and SQL-mode assumptions. For
migration work, capture both global and session values because a
connection pool or init SQL can override session state.
SELECT @@global.sql_mode AS global_sql_mode, @@session.sql_mode AS session_sql_mode, @@global.character_set_server AS global_charset, @@session.character_set_connection AS connection_charset, @@global.collation_server AS global_collation, @@session.collation_connection AS connection_collation, @@global.time_zone AS global_time_zone, @@session.time_zone AS session_time_zone, @@global.default_storage_engine AS default_engine;
If source and target differ, you have three choices: make the application/schema explicit, deliberately configure the target to preserve required behavior, or accept the new behavior and update tests/contracts. The dangerous choice is to leave the difference undocumented and hope that defaults are equivalent.
7. Deliberately wrong: copy the MySQL configuration and “fix errors until startup works”
A brute-force migration can appear efficient: copy
my.cnf from MySQL, start MariaDB, remove every
option that causes an “unknown variable” error, and declare
success when the daemon stays up. This loses intent. An option
may have been removed because MariaDB implements the feature
differently; another may still parse but have a different
default or scope; a third may correspond to a feature that needs
a new operational design.
The safer method is an option-by-option translation table with columns for source value, source purpose, target support, target equivalent, target scope, restart requirement, security/durability implications, and verification query. Unknowns remain explicit blockers until tested.
| Source dependency | Target check | Decision |
|---|---|---|
MySQL SET PERSIST automation |
Unsupported as MariaDB persistence mechanism | Rewrite to MariaDB option-file/config-management workflow |
Generic mysqldump path |
Identify exact executable vendor/version |
Call explicit mariadb-dump or
source-appropriate tool
|
| GTID variables | Compare MariaDB GTID model, do not rename blindly | Design replication/cutover separately |
| Default collation | Compare schema/column collations and sort behavior | Make required collation explicit |
| MySQL-only plugin | Check MariaDB plugin/capability alternative | Replace, redesign, or block migration |
8. Hands-on lab: version and configuration divergence notebook
Create a two-column notebook for the exact source and target. At minimum record MariaDB 12.3.2 and, when available, MySQL 8.4.11. If your real source differs, add a third column rather than pretending the course pair represents production.
SELECT VERSION(), @@version_comment;SHOW VARIABLES LIKE 'sql_mode';SHOW VARIABLES LIKE 'character_set_server';SHOW VARIABLES LIKE 'collation_server';SHOW VARIABLES LIKE 'default_storage_engine';SHOW VARIABLES LIKE 'binlog_format';SHOW VARIABLES LIKE 'gtid%';SHOW VARIABLES LIKE 'persist%';SHOW VARIABLES LIKE 'wsrep%';SHOW ENGINES;SHOW PLUGINS;
Then collect client-tool versions from the host. Mark each source dependency as same, renamed/equivalent, different semantics, absent, plugin/edition-sensitive, or not tested. Do not make server changes merely to force symmetry.
Check your understanding
- Why can MariaDB 12.x not be treated as “newer than MySQL 8.x” in a feature sense?
-
What is the important difference between
SET GLOBALand MySQLSET PERSIST? -
Why should automation call
mariadb-dumpexplicitly instead of assumingmysqldumppoints to MariaDB? - Why are defaults part of application compatibility?
- What should you do when a source option is absent on the target?
Review the answers
The products have independent release histories, so their
version numbers are not comparable coordinates.
SET GLOBAL changes runtime state; MySQL
SET PERSIST also records eligible settings
for future startup, while MariaDB uses different
persistence workflows. Explicit utility names avoid
ambiguous package aliases. Defaults affect parsing,
conversion, collation, storage and session behavior. When
a source option is absent, recover its intent, identify
the MariaDB mechanism or redesign, then verify the outcome
rather than deleting the line blindly.
9. Summary and bridge
Compatibility work starts with exact versions and exact
configuration surfaces. MariaDB and MySQL release tracks evolve
independently, utilities have diverged, MySQL’s
persisted-variable mechanism is not MariaDB’s, and defaults can
create silent behavior changes. The next lesson moves from
administration to SQL itself: JSON representation, generated
columns, collations, SQL modes, sequences, and
RETURNING are tested with result and metadata
assertions rather than feature-name comparisons.
Authoritative references
- MariaDB Foundation — current releases
- MariaDB Documentation — System Variable Differences Between MariaDB and MySQL
- MariaDB Documentation — Incompatibilities and Feature Differences
- MariaDB Documentation — Sequence Overview
- MySQL 8.4 Reference Manual — MySQL Releases: Innovation and LTS
- MySQL 8.4 Reference Manual — Persisted System Variables