PostgreSQL, MySQL, and MariaDB handle the same SQL, but their storage engines, query optimizers, and concurrency models produce very different performance profiles. MariaDB forked from MySQL in 2009 and has diverged significantly since. Picking between them based on vendor benchmarks is pointless because every vendor wins their own tests.
We installed all three on the same Rocky Linux 10 VM (4 cores, 8 GB RAM), loaded identical datasets with sysbench, and ran the same OLTP workloads against each. Same hardware, same test tool, same queries, same data size. The numbers below answer the question that matters: which one is faster for your workload?
Tested March 2026 on Rocky Linux 10.1 (kernel 6.12) with PostgreSQL 17.9, MySQL 8.4.8, MariaDB 10.11.15, sysbench 1.0.20
Quick Decision Table
If you already know your use case:
| Use Case | Best Pick | Why |
|---|---|---|
| Mixed read-write OLTP (web apps, SaaS) | PostgreSQL | Highest TPS (2,886), lowest latency (5.5ms), best MVCC |
| Read-heavy analytics, reporting | MariaDB | Highest read-only throughput (6,949 TPS) |
| Bulk INSERT workloads (logging, events) | MariaDB | 3.7x faster inserts than MySQL (8,093 vs 2,206 TPS) |
| Point lookups (caching, key-value access) | PostgreSQL | 72,664 QPS point SELECTs, 16% faster than MariaDB |
| Existing MySQL ecosystem (WordPress, etc.) | MariaDB | Drop-in replacement, faster on every workload we tested |
| Lowest memory footprint | PostgreSQL | 182 MB idle (vs 486 MB MySQL, 640 MB MariaDB) |
Test Environment
All three databases ran on the same VM, one at a time. Only one database was active during each benchmark to eliminate resource contention:
- VM: Rocky Linux 10.1, 4 vCPUs (KVM), 8 GB RAM, kernel 6.12.0
- Storage: LVM thin provisioning on SSD
- Benchmark tool: sysbench 1.0.20, running locally (no network overhead)
- Dataset: 10 tables, 100,000 rows each (total ~1 million rows per database)
- Concurrency: 16 threads (matching CPU count x4 for realistic contention)
- Duration: 60 seconds per benchmark
- Tuning: Each database was tuned with 2 GB buffer pool/shared_buffers, matching InnoDB settings where applicable
Benchmark Results
All numbers from the same sysbench OLTP workloads (identical queries across all three databases):
| Workload | PostgreSQL 17.9 | MySQL 8.4.8 | MariaDB 10.11.15 |
|---|---|---|---|
| OLTP Read-Write TPS | 2,886 | 436 | 2,758 |
| OLTP R/W Avg Latency | 5.54 ms | 36.6 ms | 5.80 ms |
| OLTP R/W p95 Latency | 8.74 ms | 90.78 ms | 9.56 ms |
| Read-Only TPS | 5,628 | 5,400 | 6,949 |
| Read-Only Avg Latency | 2.84 ms | 2.96 ms | 2.30 ms |
| Point SELECT QPS | 72,664 | 49,889 | 62,944 |
| Point SELECT Avg Lat | 0.22 ms | 0.32 ms | 0.25 ms |
| INSERT TPS | 7,255 | 2,206 | 8,093 |
| INSERT Avg Latency | 2.20 ms | 7.25 ms | 1.98 ms |
| Idle Memory | 182 MB | 486 MB | 640 MB |
| Memory Under Load | 1,129 MB | 983 MB | 916 MB |
What the Numbers Mean
PostgreSQL dominates mixed OLTP workloads. At 2,886 transactions per second with 5.54ms average latency, PostgreSQL handled 6.6x more mixed read-write transactions than MySQL and 5% more than MariaDB. Its MVCC implementation (multi-version concurrency control) excels when readers and writers compete for the same rows.
MariaDB is the fastest for pure reads and inserts. At 6,949 read-only TPS and 8,093 insert TPS, MariaDB outperformed both competitors on single-operation workloads. MariaDB’s InnoDB fork has diverged significantly from MySQL’s, with optimizations for table scan performance and bulk insert handling.
MySQL 8.4 underperforms significantly. MySQL delivered 436 OLTP TPS versus PostgreSQL’s 2,886 and MariaDB’s 2,758. The 36.6ms average latency (6.6x slower than PostgreSQL) suggests InnoDB’s row-locking and redo log handling in MySQL 8.4 creates more contention under concurrent workloads than either competitor. MySQL’s INSERT throughput (2,206 TPS) was 3.7x slower than MariaDB’s 8,093 TPS on the same InnoDB engine.
PostgreSQL uses the least memory at idle. At 182 MB idle versus MySQL’s 486 MB and MariaDB’s 640 MB, PostgreSQL’s process-per-connection model starts lighter. Under load, all three converge (916 MB to 1,129 MB) because the buffer pool dominates memory usage.
PostgreSQL 17.9
PostgreSQL uses MVCC with a separate process per connection and a sophisticated query planner that gets smarter as tables grow. Version 17 added incremental backup, SQL/JSON improvements, and significant performance gains for bulk loading and vacuuming.
Install and initialize on Rocky Linux 10:
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-10-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf install -y postgresql17-server postgresql17-contrib
sudo /usr/pgsql-17/bin/postgresql-17-setup initdb
sudo systemctl enable --now postgresql-17
Benchmark tuning applied:
ALTER SYSTEM SET shared_buffers = '2GB';
ALTER SYSTEM SET work_mem = '256MB';
ALTER SYSTEM SET effective_cache_size = '4GB';
ALTER SYSTEM SET max_connections = 200;
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
ALTER SYSTEM SET wal_buffers = '64MB';
PostgreSQL also ships with pgbench, its built-in TPC-B benchmark tool. On the same hardware with a 10 million row dataset (scale factor 100), pgbench measured 109,026 read-only TPS and 2,006 mixed read-write TPS.
| Strength | Limitation |
|---|---|
| Best OLTP throughput and latency | Higher memory under load (1,129 MB) |
| Lowest idle memory (182 MB) | Process-per-connection can be costly at very high connection counts |
| Advanced features: pgvector, JSON, CTEs, window functions | No multi-source replication without third-party tools |
| MVCC never blocks readers | VACUUM overhead for long-running transactions |
MySQL 8.4.8
MySQL 8.4 LTS is Oracle’s long-term support branch. It uses InnoDB as the default storage engine with row-level locking and crash recovery. MySQL 8.4 dropped the Query Cache entirely and focuses on the InnoDB adaptive hash index for read performance.
Install on Rocky Linux 10 (note: the MySQL GPG key expired on Rocky 10, requiring --nosignature during RPM install):
sudo dnf install -y https://dev.mysql.com/get/mysql84-community-release-el10-1.noarch.rpm
sudo dnf download mysql-community-common mysql-community-client-plugins mysql-community-libs mysql-community-client mysql-community-icu-data-files mysql-community-server --destdir=/tmp/mysql-rpms
sudo rpm -ivh --nosignature /tmp/mysql-rpms/*.rpm
sudo systemctl enable --now mysqld
Benchmark tuning:
SET GLOBAL innodb_buffer_pool_size = 2147483648;
SET GLOBAL max_connections = 200;
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
| Strength | Limitation |
|---|---|
| Widest ecosystem (WordPress, Drupal, most PHP apps) | Slowest on every workload we tested |
| Oracle commercial support available | 36.6ms OLTP latency (6.6x slower than PostgreSQL) |
| MySQL Shell, InnoDB Cluster for HA | INSERT throughput 3.7x slower than MariaDB |
| Group Replication built in | GPG key issues on newer Linux distros (Rocky 10) |
MariaDB 10.11.15
MariaDB is a community fork of MySQL with significant divergence since the split. MariaDB 10.11 is the current Long Term Support release (maintained until February 2028). Its InnoDB implementation has diverged from MySQL’s, with different buffer pool management, a pluggable encryption architecture, and the Aria storage engine for internal temporary tables.
Install on Rocky Linux 10 (available from the base repos):
sudo dnf install -y mariadb-server
sudo systemctl enable --now mariadb
Benchmark tuning (/etc/my.cnf.d/bench.cnf):
[mysqld]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
max_connections = 200
innodb_flush_log_at_trx_commit = 1
MariaDB required no GPG workarounds and installed cleanly from the base Rocky Linux repos. For detailed installation on both RHEL and Debian families, see our MariaDB installation guide.
| Strength | Limitation |
|---|---|
| Fastest reads (6,949 TPS) and inserts (8,093 TPS) | Higher idle memory than PostgreSQL (640 MB) |
| Drop-in MySQL replacement for most apps | JSON support less mature than PostgreSQL |
| Ships in default RHEL/Rocky/Debian repos | Diverging from MySQL compatibility on newer features |
| Galera Cluster for synchronous multi-master replication | No native logical replication (uses Galera or standard replication) |
Workload Deep Dive
OLTP Read-Write (Mixed Transactions)
This workload combines SELECT, UPDATE, INSERT, and DELETE operations in a single transaction, simulating a typical web application workload (shopping carts, user management, content updates).
sysbench /usr/share/sysbench/oltp_read_write.lua \
--tables=10 --table-size=100000 --threads=16 --time=60 run
PostgreSQL (2,886 TPS) and MariaDB (2,758 TPS) were nearly identical, both delivering 6x the throughput of MySQL (436 TPS). The gap is explained by how each database handles concurrent transactions: PostgreSQL’s MVCC allows readers to proceed without blocking writers, while MySQL 8.4’s InnoDB creates more lock contention in mixed workloads.
Point SELECT (Key-Value Lookups)
This test measures single-row lookups by primary key, the most common query pattern in caching layers and API backends.
sysbench /usr/share/sysbench/select_random_points.lua \
--tables=10 --table-size=100000 --threads=16 --time=60 run
PostgreSQL delivered 72,664 QPS with 0.22ms average latency, 16% faster than MariaDB (62,944 QPS) and 46% faster than MySQL (49,889 QPS). For key-value access patterns, PostgreSQL’s index-only scans and buffer manager are highly optimized.
INSERT Throughput
Pure INSERT workloads stress the write-ahead log (WAL/redo log), buffer pool, and index maintenance:
sysbench /usr/share/sysbench/oltp_insert.lua \
--tables=10 --table-size=100000 --threads=16 --time=60 run
MariaDB (8,093 TPS) edged out PostgreSQL (7,255 TPS) and crushed MySQL (2,206 TPS). MySQL’s INSERT performance was 3.7x slower than MariaDB on the same InnoDB engine, which points to differences in how the two forks handle redo log flushing and batch insert optimizations.
Feature Comparison
Performance is one dimension. The right database also depends on features, ecosystem, and operational characteristics:
| Feature | PostgreSQL 17 | MySQL 8.4 | MariaDB 10.11 |
|---|---|---|---|
| Default storage engine | Heap (with MVCC) | InnoDB | InnoDB (forked) |
| ACID compliance | Full | Full (InnoDB) | Full (InnoDB) |
| JSON support | Native JSONB with indexing | JSON type | JSON type (LONGBLOB alias) |
| Full-text search | Built in (tsvector) | InnoDB FTS | InnoDB FTS + Mroonga |
| Replication | Streaming + Logical | Binlog + Group Replication | Binlog + Galera Cluster |
| Vector search | pgvector extension | No native support | No native support |
| Partitioning | Declarative (native) | Range, List, Hash, Key | Range, List, Hash, Key + System versioned |
| Window functions | Full SQL:2011 | Full | Full |
| CTEs (WITH queries) | Recursive + materialized | Recursive | Recursive |
| Default in RHEL repos | No (PGDG repo) | No (Oracle repo) | Yes |
| License | PostgreSQL (MIT-like) | GPL v2 | GPL v2 |
Benchmark Methodology
For reproducibility, here are the exact sysbench commands used. The sysbench documentation covers additional workload types and configuration options.
Prepare the test data (identical for MySQL, MariaDB, and PostgreSQL):
# MySQL / MariaDB
sysbench /usr/share/sysbench/oltp_read_write.lua \
--mysql-host=localhost --mysql-user=bench --mysql-password='password' \
--mysql-db=sbtest --tables=10 --table-size=100000 prepare
# PostgreSQL
sysbench /usr/share/sysbench/oltp_read_write.lua \
--pgsql-host=localhost --pgsql-user=bench --pgsql-password='password' \
--pgsql-db=sbtest --db-driver=pgsql --tables=10 --table-size=100000 prepare
Run the benchmark:
sysbench /usr/share/sysbench/oltp_read_write.lua \
--mysql-host=localhost --mysql-user=bench --mysql-password='password' \
--mysql-db=sbtest --tables=10 --table-size=100000 \
--threads=16 --time=60 --report-interval=10 run
Each database was given a 2 GB buffer pool (shared_buffers for PostgreSQL, innodb_buffer_pool_size for MySQL/MariaDB). Only one database ran at a time. The VM was idle except for the benchmark and the database under test.
When to Choose Each Database
Choose PostgreSQL when you need the best mixed-workload performance, advanced SQL features (CTEs, window functions, JSONB), vector search with pgvector, or when memory efficiency at idle matters (containers, small VMs). PostgreSQL is the fastest growing database in the industry for a reason.
Choose MariaDB when you are running MySQL-compatible applications (WordPress, Joomla, Magento) and want better performance without changing code. MariaDB outperformed MySQL on every single workload in our tests. It ships in the default RHEL/Rocky/Debian repos, making it the path of least resistance for MySQL-compatible deployments.
Choose MySQL when your application specifically requires MySQL (Oracle MySQL certifications, specific MySQL Shell features, or InnoDB Cluster). Be aware that MariaDB is a drop-in replacement that performs better on the same workloads, so the reason to choose MySQL should be ecosystem-specific, not performance-based.