GuidesMySQL or MariaDB

MySQL or MariaDB for your own database server

[object Object]

Tested on Updated January 1, 1970

Recommended server for this guide

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy · 2 vCPU · 8 GB Memory · 60 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€8.99/mo

Deploy now
On this page

The short answer

Pick MariaDB for WordPress and most PHP apps, and whenever the app just says "MySQL or MariaDB". In our test it wrote faster, restored a dump in half the time, has its physical backup tool in the same image, and has a non-profit foundation next to the company behind it.

Pick MySQL when the app says "MySQL 8 or newer" and means it: it uses SQL that only MySQL understands, such as ->> on JSON columns, or it needs Group Replication, InnoDB Cluster or MySQL's document store. MySQL read slightly faster, started with less memory, and its JSON is a real binary type.

What we tested

Both ran on the same Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13, set up exactly as in our guides: MySQL under the user mysql, and MariaDB under the user mariadb, each a single rootless Podman container with the official image. Both guides use the same memory settings: a 4 GB InnoDB buffer pool, a 1 GB redo log, 200 connections and 64 MB for temporary tables.

Both guides use port 3306, so for this test MySQL listened on 3307: one line, port = 3307, in its server.cnf, and -P 3307 in its health check. To keep the measurements fair, the benchmarks and restores ran with the other server stopped; the rest ran with both up and the other idle.

MySQLMariaDB
VersionCommunity Server 9.7.2 (LTS)12.3.3 (LTS)
Install, following our guide49 seconds36 seconds
Containers11
Image952 MB346 MB
Memory after a reboot, idle796 MB1,179 MB
Memory after the benchmarks3.1 GB2.8 GB
Data on disk, empty1.2 GB1.1 GB
Data on disk, after all tests8.4 GB, of which 5.1 GB binary log3.1 GB
Read-only, 16 clients (transactions/s)800771
Read-write, 16 clients359499
Write-only, 16 clients6521,455
Load 8 million rows (sysbench prepare)195 seconds124 seconds
Dump everything, our guide's script154 seconds162 seconds
Restore the 1.9 GB dump375 seconds177 seconds
Physical backup104 seconds, Percona XtraBackup, separate 1.56 GB image26 seconds, mariadb-backup, in the image

Memory is the proportional set size (PSS) of mysqld and mariadbd. Disk is the data volume; both start at about 1 GB because both guides set a 1 GB redo log.

Speed

We used sysbench 1.0.20 from Debian on a 1.9 GB database, eight tables of a million rows, so everything fitted in the cache. After a two-minute warm-up, each test ran for 60 seconds, twice, at 1, 4, 16 and 64 clients. The table shows the average in transactions per second:

TestClientsMySQLMariaDB
Read-only1352304
4838724
16800771
64732731
Read-write1101111
4235399
16359499
64431525
Write-only1198438
44631,040
166521,455
641,1272,016

MySQL read up to 15 % faster with few clients; at 64 they were equal. MariaDB was ahead at read-write from 4 clients, and about twice as fast at pure writes.

Most of the write difference is one default. MySQL keeps a binary log of every change, written to disk at each commit, which replication and restoring to a point in time use. MariaDB has it off until you switch it on. We ran the write tests again with that swapped, at 16 clients:

MySQLMariaDB
Both without binary log, read-write506499
Both without binary log, write-only1,0271,455
Both with binary log, read-write359442
Both with binary log, write-only6521,013

Without it on both, read-write was even; with it on both, MariaDB was 23 % ahead. At pure writes, MariaDB stayed 40 to 55 % ahead either way. If you need the binary log, for a replica or for point-in-time recovery, switch it on in MariaDB and count on that speed, not the higher one.

The same binary log made MySQL slower at loading data: restoring the dump took 375 seconds against MariaDB's 177, and loading the test data 195 against 124.

Setup and day-to-day use

Both guides are the same length and the same shape, and both servers came back by themselves after a reboot. The differences:

  • MySQL's image is almost three times larger, 952 MB against 346 MB. It also holds MySQL Shell.
  • MySQL needs one extra setting in our guide, net.ipv4.ip_nonlocal_bind, to start before WireGuard at boot. MariaDB listens on the tunnel address even before it exists.
  • MySQL also listens on port 33060 for its X Protocol unless you switch it off, as our guide does.
  • The client. Debian has no MySQL client from Oracle. Its mysql command comes from MariaDB, and it worked with both servers, over TLS too.
  • Characters inside the container. In the MySQL image, podman exec mysql mysql talks latin1, since the image has no locale. A name with "Å" typed or piped that way was stored garbled. Dumps are not affected, since they set the character set themselves; for anything else, add --default-character-set=utf8mb4. MariaDB's client used utf8mb4.

Memory went the other way from what the images suggest: after a reboot, MariaDB used 1.2 GB and MySQL 800 MB, since MariaDB sets up part of its cache when it starts. Under load both grew towards the 4 GB we gave them.

Do not run both on one 8 GB server with 4 GB of cache each. We did, and when both had filled their caches, a restore into MySQL stalled the whole server for minutes while the kernel looked for memory. Run one per server, as the guides say, or halve both caches.

The same app on both

We ran one app's schema and queries through Python's PyMySQL on both: a customers table and an orders table with a foreign key, a CHECK, a JSON column, and a column generated from the JSON with an index. These worked the same on both:

  • foreign keys, CHECK constraints and generated columns, which refused the same bad rows;
  • JSON_EXTRACT, JSON_UNQUOTE, JSON_SET, JSON_CONTAINS, JSON_TABLE, JSON_OBJECT, JSON_ARRAYAGG and JSON_SCHEMA_VALID;
  • window functions, recursive WITH, EXCEPT, REGEXP_REPLACE, GROUP_CONCAT;
  • INSERT ... ON DUPLICATE KEY UPDATE with VALUES();
  • 'anna astrom' finding "Anna Åström", since both compare text without case and accents by default.

These only worked in MySQL, and MariaDB answered with a syntax error:

  • meta->>'$.sku' and meta->'$.tags', MySQL's short form for JSON_EXTRACT;
  • INSERT ... AS new ON DUPLICATE KEY UPDATE name = new.name;
  • LATERAL subqueries;
  • MEMBER OF, and indexes on JSON arrays (CAST(... AS CHAR(20) ARRAY)).

And these only in MariaDB: INSERT ... RETURNING, sequences and tables that keep their own history (below).

WordPress 7.1.3 installed with wp-cli on both, and creating posts and comments and a search-and-replace of the site address worked the same. WordPress recommends MySQL 8.0 or MariaDB 10.11 or newer, so both are well inside that.

JSON

In MySQL, JSON is a type of its own, stored in a binary format. In MariaDB, JSON is another name for LONGTEXT, with a check that the text is valid JSON:

`doc` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`doc`))

Both refused 'not json'. The difference shows in what you get back. We stored {"b":1, "a":2, "a":3}, with a duplicate key, in both:

MySQLMariaDB
Stored and returned{"a": 3, "b": 1}{"b":1, "a":2, "a":3}
JSON_EXTRACT(doc, '$.a')32

MySQL sorts the keys, removes duplicates keeping the last, and normalises spaces. MariaDB keeps the text as written. For apps that write JSON and read it back through the JSON functions, both work. Apps that compare JSON as text, or rely on MySQL's ->>, notice.

Features where they have parted ways

We tried each on its own server:

  • Sequences (MariaDB): CREATE SEQUENCE invoice_no START WITH 1000 and NEXTVAL() gave 1000, 1001. MySQL has no sequences; use AUTO_INCREMENT.
  • Tables with history (MariaDB): a table WITH SYSTEM VERSIONING kept the old price after an update, and FOR SYSTEM_TIME AS OF showed the table as it was a second earlier. MySQL has nothing like it.
  • Galera (MariaDB): the library for multi-primary clusters is in the image, ready for wsrep_on. We did not build a cluster, which takes three servers.
  • Spider (MariaDB), the engine that spreads a table over several servers, is not in the official image: INSTALL SONAME 'ha_spider' found no file.
  • Group Replication and InnoDB Cluster (MySQL): the group_replication plugin installed, and MySQL Shell 9.7.1 is in the image. We did not build a cluster either.
  • Document store (MySQL): with the X Protocol switched on for the test, MySQL Shell added JSON documents to a collection and searched them, with no SQL. MySQL stores the collection as a table with a JSON column.
  • JSON duality views (MySQL): a view that shows rows as JSON documents, and inserts and updates through it, worked in the Community version.
  • Thread pool: MySQL 9.7.2 Community loaded its thread_pool plugin with plugin_load_add, though Oracle's page still lists Thread Pool under Enterprise Edition. MariaDB has one built in: thread_handling = pool-of-threads switched it on.
  • Vectors: both have a vector type and can compare vectors, with different function names.

Accounts and passwords

New accounts get different password methods:

  • MySQL: caching_sha2_password. The older mysql_native_password is not loaded in 9.7: creating an account with it failed with Plugin 'mysql_native_password' is not loaded.
  • MariaDB: mysql_native_password, the older method based on SHA-1. MariaDB 12.3 also has caching_sha2_password, as a plugin you install; an account made with it logged in over TLS. Ed25519 and PARSEC, MariaDB's stronger methods, are in the image too.

Every client we used, the MariaDB client, PyMySQL and PHP's mysqlnd, worked with both. Since MySQL 9.7 does not load mysql_native_password, an old client that only knows that method cannot log in to it.

Accounts do not move between them with their passwords. MySQL's password hashes did not work in MariaDB, even with the same method; create the accounts again with their passwords.

Moving and replicating between them

A dump from MySQL into MariaDB loaded, apart from the index on a JSON array, which MariaDB does not have. MariaDB accepted MySQL's default collation, utf8mb4_0900_ai_ci, and turned the JSON columns into its LONGTEXT with a check.

A dump from MariaDB into MySQL did not load. MySQL did not know MariaDB's default collation, utf8mb4_uca1400_ai_ci. After we replaced it with utf8mb4_0900_ai_ci, MySQL still refused the rows of the orders table, because mariadb-dump writes the values of generated columns, and refused the table with history.

Replication from MySQL to MariaDB worked until the first JSON column. MariaDB connected as a replica over TLS, with a caching_sha2_password account, and copied new databases, tables, inserts, updates and deletes. The first row with JSON stopped it: Slave received unknown field type field 245, MySQL's binary JSON. Without JSON columns, it could carry you through a move from MySQL to MariaDB.

Replication from MariaDB to MySQL did not work. MySQL has global transaction IDs (GTIDs) on by default in this image, and refused a source without them. With ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS = LOCAL, it connected, but stopped at once with Found invalid event in binary log. The two GTID formats, uuid:1-870565 in MySQL and 0-2-119448 in MariaDB, have nothing in common.

Updates and backups

Updates. Both images update their bug and security fixes with podman auto-update. MySQL's LTS releases are supported for 5 years, plus 3 of extended support, and the next one comes after about two years. 9.7 is the last with that numbering; the next use the year and month, such as 26.7. MariaDB makes a long-term release every year, supported for three years: 12.3, from May 2026, until June 2029. Both upgraded in our guides by changing the image tag, MySQL from 8.4 and MariaDB from 11.8.

Dumps took the same time, about two and a half minutes for everything with our guides' scripts, and gave the same size, 768 MB compressed. Restoring was where MySQL was slower, as above. MySQL keeps 30 days of binary log by default; our guide keeps seven, and in our tests it still grew to 5.1 GB, more than the data itself. Count on the disk for it.

Physical backups, which copy the data files for fast restores of large databases, differ the most. mariadb-backup is part of MariaDB's image and took 26 seconds. MySQL's own tool, MySQL Enterprise Backup, is in the paid Enterprise Edition, so our guide uses Percona XtraBackup: a separate 1.56 GB image, 104 to 112 seconds for the same data, and for 9.7 only a release candidate, 9.7.1-rc1, when we tested.

Licence and cost

Both servers are open source under the GPL version 2 and cost nothing. Who stands behind them differs, as their own pages said when we checked on 14 October 2026.

MySQL belongs to Oracle, code and trademark. Oracle sells the same server under a commercial licence too, for products that include it, and sells MySQL Enterprise Edition, with Enterprise Backup, encryption of data on disk, a firewall, audit logging, data masking and support around the clock. Its page shows no prices. In February 2026, Percona and others in the MySQL community published an open letter asking Oracle to talk about a foundation for MySQL; Percona's letter says Oracle cut MySQL's staff by about half in autumn 2025.

MariaDB is developed mostly by the company MariaDB plc, which an investment firm, K1, took private in 2024, together with the MariaDB Foundation, a non-profit funded by sponsors. The Foundation's page says that MariaDB Server "will remain Free and Open Source Software licensed under GPLv2, independent of any commercial entities". Not everything from the company is open source: its database proxy, MaxScale, uses the Business Source License, free in production for fewer than three servers. The company also sells MariaDB Enterprise Server and support.

Neither choice locks you in to paying anything. With MariaDB, more of what you might need later, such as a physical backup tool, a thread pool and a cluster library, is in the free version.

Which one to pick

Check what your app says first: "MySQL 5.7 or MariaDB 10.x" means either works. If you are unsure, test the app's own setup against both; it takes a few minutes with these guides. Moving our test app from MySQL to MariaDB was a dump and a restore, while the other way needed the dump fixed by hand.

Run it on your own server

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy

€8.99/mo

vCPU
2
Memory
8 GB
Storage
60 GB
Transfer
10 TB
Performance
SSD · RAID 1
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides