MariaDB versions, measured — four pairs, no reportable difference
MariaDB versions, measured — four pairs, no reportable difference
Four MariaDB version pairs were measured properly, on the same machines, with the same real shop's data. Not one of them cleared its own control. The version you run does not matter for this application; the engine does, and there the answer is hard — 6amMart is a MariaDB application, and on MySQL it is a tree that does not work correctly.
The most useful thing this round produced was the discovery that its own first set of database numbers was invalid, and what invalidated them. That is the section below, because the same mechanism will quietly corrupt anyone else's database benchmark the same way.
The short answer
Take whatever MariaDB your release carries. A native install takes it from the release's own archive — 11.8 on Ubuntu 26.04 and Debian 13, 10.11 on Ubuntu 24.04 — so security fixes arrive through the distribution and no third-party repository sits in the serving path.
| Question | Answer | Confidence |
|---|---|---|
| MariaDB or MySQL? | MariaDB. MySQL is a code port, not a tuning choice | settled in the source, not by benchmark |
| 10.11 or 11.8? | Wash. Take the archive's | four version pairs, none cleared its control |
| Is 12.3 worth adding a repository for? | No — nothing measurable, and two install workarounds | measured back-to-back |
| What actually moves the number? | Memory up to the point the working set fits, then the query plans | measured |
If you want the decision rather than the evidence, which database engine is the shorter page.
The first database comparison was invalid, and the floor is what gave it away
The round's database battery opens with SELECT 1 — a statement that does no work whatsoever, and asks the server to hand back a constant. It exists precisely to establish the floor, so that the real queries can be read against it.
It read 12 ms on one arm against 29 ms and 37 ms on the other two. A floor that moves three times over is not query execution. Nothing about handing back a constant can differ that much between two builds of the same database.
The cause was the connection, not the query. MariaDB 11.8.6 negotiates TLS on a unix-socket connection; 10.11.14 does not. Nothing required it: neither server set a certificate path, and neither required secure transport. 11.8 generates a certificate and enables it on its own, and both ends support it, so it happens.
| MariaDB 10.11.14 | MariaDB 11.8.6 | |
|---|---|---|
| Encryption available | disabled | yes |
| Cipher negotiated over the local socket | none | TLS_AES_256_GCM_SHA384 |
The battery opened a fresh connection for every sample, so it was timing a TLS handshake and attributing it to database speed.
Every database row measured before the fix was discarded, and that is the honest state of it — there is no clean per-query total to publish from that round. The version conclusion below rests on the whole-application comparisons instead, which were re-measured afterwards and are a wash.
Your shop never pays that cost
PHP's database driver does not negotiate TLS over a unix socket. That is measured, not assumed — through the driver on both machines, the live connection reports Ssl_cipher=NONE at 0.12 to 0.21 ms per connect. No customer-facing request is affected, and 11.8 is not disqualified as a shop database.
The admin panel did pay it
The panel reaches the database by running the command-line client rather than through a driver, and that client does negotiate TLS on a socket. So every panel page that reads the database was paying the full cost, several times over — the database page, the index advisor reading the server's own catalogue, the nightly maintenance sweep, the health rows, the backup verification's row counts.
| Arm | Default | With TLS off on the socket |
|---|---|---|
| MariaDB 11.8.6 | 24 ms | 6 ms |
| MariaDB 10.11.14 | 10 ms | 10 ms — no change, as expected |
Thirty invocations of one counting statement, the same statement and the same data on both arms. Connect cost alone: 8 ms on 10.11, 22 to 25 ms on 11.8, 6 ms with it off.
Fixed by turning it off on every local invocation. A unix socket on the same machine, scoped by file permissions, never crossing a network — the encryption protects nothing there.
The version pairs, measured properly
A database swap costs minutes, so these could not run in a strictly alternating order. Instead each ran as A, B, A — the original version, the new one, then back to the original. The third leg is the control, and it earned its place twice in this round.
MariaDB 11.8 against 12.3, on Ubuntu 26.04
One machine, PHP held identical on both sides, same data, same tuning — 1152 MB buffer pool, 128 MB temporary tables, trx_commit=1, 601 indexes.
The same question, measured three times on the same machine:
| Comparison | Median |
|---|---|
| 12.3 against 11.8 as measured that morning | −5.1 % → 12.3 looks faster |
| 12.3 against 11.8 measured back-to-back | +1.8 % → 12.3 is level or slightly behind |
| The same 11.8, morning against back-to-back | −7.8 % → 11.8 got faster |
The same version, on the same machine, measured 7.8 % faster the second time. That is the tell, and it is not noise — it was monotonic across nearly every row.
What differed was the state of the database files, not the version. The morning's 11.8 ran on the original files, in place since the data was imported. 12.3 ran on those same files, upgraded in place. The back-to-back 11.8 ran on a fresh set, restored from a dump minutes earlier — and a restore rewrites every table and index compactly, with no fragmentation, no leftover page splits, and fresh statistics.
So "12.3 is 5 % faster" was file freshness measured against a version label.
Verdict: level. 12.3 was never ahead once the comparison was taken back-to-back on comparable files. And 12.3 would cost a third-party repository, a rolling release cadence and two install workarounds in exchange for nothing measurable.
MariaDB 10.11 against 11.8, on Ubuntu 24.04
One machine, A, B, A — 10.11, then 11.8 upgraded in place so the file lineage is identical, then back to 10.11.
| Leg | Against leg A | |
|---|---|---|
| B — 11.8 | −2.7 %, ahead on 14 of 14 rows | looks like a real win |
| C — 10.11 again | −5.0 % | the control, and it fails |
| C against B | −2.2 %, 10.11 now ahead on 10 of 14 |
10.11 measured 5.0 % faster than itself — a bigger gap than the 2.7 % that separated the two versions — and on its second outing it beat 11.8 on 10 of 14 rows. Twelve of 14 rows got monotonically faster from A to B to C regardless of which version was running. That is session drift, not a version effect.
MariaDB 10.11 against 11.4, on Debian 12
| Leg | Version | The 12 app rows clean in all three legs | Against leg A |
|---|---|---|---|
| A | 10.11.18 (archive) | 449.5 ms | — |
| B | 11.4.13 (upstream repo) | 447.5 ms | −0.4 % |
| C | 10.11.19 again | 451.1 ms | +0.4 % |
Control rows: 3.0 ms to 3.0 ms, −1.7 %. Rows won: A 5, B 3, C 4. The version difference is smaller than the drift its own control shows, and no arm wins a majority of rows.
One leg of this had to be recomputed, and it is a worked example of the trap. All six of leg A's storefront passes had recorded server errors at a p50 of 0.3 ms — a prior failed swap had stopped the writers and never restarted them. An error answers in a third of a millisecond, so that row was making leg A look spectacular. The totals above are computed on the 12 rows that are clean successes in all three legs, not 14. The earlier printing of this table, which included the tainted row, has been withdrawn.
Why not MySQL — and this one is not a benchmark result
This is the part people are surprised by, because MySQL and MariaDB are usually described as interchangeable. For this codebase they are not, and the reason was found by reading the application's source rather than by timing it.
A query-optimiser setting the code depends on. The item-search controller issues a session-level statement switching off a MariaDB-only optimiser flag, because MariaDB otherwise re-evaluates a subquery per row and the search query needs it off. MySQL rejects the statement outright with an error, and the shop's search endpoint returns a server error on every request.
Case handling in the system catalogue. Four migrations read table and column metadata from the server's own catalogue in lower case. MySQL 8 returns it upper case, so those migrations die and every later one stays pending — leaving the schema part-applied with no obvious sign of it.
Neither is guarded. Both are silent on MariaDB, so nothing in a normal build surfaces them, which is exactly why this had to be checked in the code and not inferred from a benchmark.
So MySQL is not "slightly slower here". It is a port — roughly a day of work, plus a full re-test of every report screen. Not recommended. If your host only offers MySQL, that is worth knowing before you buy the hosting rather than after.
Both MySQL versions have a separate problem: 8.0 has reached end of life and receives no further security fixes at all. If MySQL is forced on you, 8.4, not 8.0.
The claim this round withdrew
Earlier material on this site said 10.11, and not the newest MariaDB, on the strength of one figure: an admin report measured roughly 2.7× slower on 11.x.
That claim is withdrawn as a claim about 11.8, and it is worth saying exactly why rather than quietly dropping it.
The 2.7× came from one report query on MariaDB 11.0's cost model, in an earlier round on the container stack. It was real on 11.0. It does not describe 11.8, and nothing resembling it appeared on any row of any 11.8 comparison above.
The general point survives the number
Newer is not automatically faster for a fixed application. A planner change that helps most workloads can hurt one particular set of queries, which is exactly what 11.0 did to one report — and the only way to know is to measure your own. What changed is that we measured again on 11.8 and the effect was not there.
What "tested against" means, and what it no longer means
10.11 is the version the optimised codebase was measured on, the version its query plans were checked against, and the version its automated tests ran on. Every figure on the measured results page was taken on it.
That used to be the argument for pinning it. The identical-server round added the other half: 11.8 was put through the same shop and the same queries and did not behave differently, so knowing what the queries do on 10.11 no longer means having to stay there.
Memory matters more than the version
On a 3.9 GB server with a real shop's data — a 516 MB database, 66,701 orders — a 1152 MB buffer pool held effectively the entire working set: a buffer-pool hit rate of 99.8 %, meaning virtually every read was answered from memory rather than disk.
That single fact does more for a shop's speed than any version choice on this page. A database that never waits on storage during normal operation is the goal.
There is a limit to that argument, and it is a threshold rather than a dial. On one comparison machine the buffer pool was raised from 256 MB to 1152 MB — four and a half times larger — and the database battery did not move at all. The internals genuinely improved: cache hit rate 99.856 % to 99.930 %, temporary tables spilling to disk 47.3 % down to 22.1 %. The response times did not follow, because those reports are processor-bound work over rows that were already in memory.
Memory buys you everything up to the point where the working set fits, and close to nothing after that.
Where the real database wins came from
Not from a version. Two findings from the same dataset, both worth more than every version pair on this page:
An index set that nobody had applied. On the untouched CodeCanyon tree — the codebase most buyers run — a measured pack of 38 indexes read 34 missing. On the optimised fork the same indexes arrive as migrations, so every test shop had shown green and the gap was invisible. A measured index set that depends on someone finding a button is not applied; it is now a step at the end of every path that puts data into a project's database. Proven on a real vendor shop: 4 covered to 40 covered in 1.0 s.
Two report shapes no index pack covered. A single-column index on a status column where one value matches half the table gets taken as a range, and then costs one row lookup per matching row. Which is why no server setting moved these two rows in any round. Two covering indexes, measured against each other on one machine, medians of 7 over two interleaved rounds:
| Without | With | |
|---|---|---|
| Store report — sum per store | 151 / 167 ms | 36 / 36 ms |
| Earning report — per month | 181 / 182 ms | 77 / 78 ms |
Build time on 66,701 orders: 0.3 s and 0.2 s.
For context, the shape of the battery those two sit in — medians of 7, on 66,701 orders, with the client round trip itself at 10.4 ms:
| Statement | ms |
|---|---|
| Count orders | 19.8 |
| Orders joined to details, 50 newest | 10.8 |
| Item listing, active and paged | 11.4 |
| Item search by name | 15.4 |
| Store report — sum per store | 152.0 |
| Earning report — per month | 176.7 |
Every hot-path shape is within 5 ms of the floor. The two report shapes are the outliers, and they are the ones the covering indexes fixed. The plan, not the sizing, is the cost.
Things measured and deliberately not built
Published because a decision not to do something is also a result:
- Temporary tables in RAM. An earlier round left on-disk temporary tables at 59.8 % as an open item. Measured under the real public API workload: 6 on-disk temporary tables in 115 requests, and 5 of the 6 were catalogue reads at 1.8 ms each, behind a response cache. Not a data query, and not worth a RAM-backed temporary directory and its out-of-memory surface.
- Adaptive hash index, thread pool, persistent PHP connections. No measurement on this dataset showed a shape any of them would help — the hot paths are within 5 ms of the client floor — and each carries a known contention or resource cost. Left at the distribution's values.
What this does not tell you
Every figure here is from a 2-core, 3.9 GB server. We have not measured larger, so nothing here predicts what 8 GB would do.
Nothing here describes your catalogue, which is a different size and shape from the one measured.
And the four version pairs above are four pairs, on one application, on two release families. They are not a general statement about MariaDB.
Related
The OS and stack round is where the database axis sits among the other five. PHP versions, measured is the same shape of finding on a different component. How we measure covers the A, B, A design, the control rows, and why the file-freshness effect makes the third leg mandatory.
For the decision rather than the evidence: which database engine.