How to Install MariaDB on Ubuntu 24.04 — Production Database Server
MariaDB is the default relational database on most modern Linux distributions for a reason. It speaks the MySQL wire protocol, runs every query MySQL runs, and adds genuinely useful features on top — open governance, better query optimization, pluggable storage engines, and synchronous multi-master replication. This guide walks you through installing MariaDB 11 on an Ubuntu 24.04 VPS, from adding the official apt repository to tuning InnoDB for your workload, enabling binary logging for replication, introducing Galera clustering, and requiring TLS on every client connection.
Running an existing MySQL stack? MariaDB is a drop-in replacement for most applications. If you are evaluating the switch, see our internal guide on choosing a MySQL alternative before you migrate.
Table of Contents
Why MariaDB Instead of MySQL on a VPS?
MariaDB was forked from MySQL in 2009 by Michael "Monty" Widenius, MySQL's original author, shortly after Oracle's acquisition of Sun Microsystems gave them control of the project. Fifteen years later the two databases have diverged enough that the choice matters — even though on the surface they run the same SQL.
Open governance. MariaDB is stewarded by the non-profit MariaDB Foundation. Its development roadmap, security disclosures, and source code are fully public, and no single commercial vendor can change the license or pull a feature behind a paywall. MySQL, by contrast, is an Oracle product where the community edition lags the enterprise edition on features like thread pooling, audit logging, and hot backups. For hobbyists this difference is philosophical. For businesses, it means you keep access to the full feature set without buying a commercial license.
Better default performance. MariaDB ships with a smarter query optimizer, a thread pool that is free (MySQL's thread pool is enterprise-only), and storage engines that MySQL does not have: Aria for crash-safe MyISAM-style tables, ColumnStore for analytical workloads, Spider for transparent sharding, and MyRocks for write-heavy applications. On a small VPS these extras rarely matter, but if you ever outgrow a single node they give you options that MySQL does not.
Galera is bundled. Synchronous multi-master replication is a first-class feature of MariaDB. Setting up a three-node Galera cluster takes a few config lines. MySQL's equivalent is Group Replication plus MySQL Router, which is more complex to operate and not as well tested at small scale.
Full backward compatibility. Applications that speak MySQL — WordPress, Nextcloud, GitLab, phpMyAdmin, every major ORM — connect to MariaDB without code changes. The mysql client binary is aliased to mariadb and vice versa. Your existing mysqldump backups restore into MariaDB cleanly.
For a single VPS running a CMS, ticketing system, or application database, MariaDB gives you more headroom and more options than MySQL — at the same cost of zero.
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- At least 2 GB of RAM for production workloads (4 GB+ recommended)
- At least 20 GB of free disk space on the partition holding
/var/lib/mysql
Recommended Plan: Starter>
For a single-application database serving a small-to-medium site (WordPress, Ghost, Nextcloud, or similar), we recommend the Starter plan:>
- 4 vCPU cores
- 8 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth>
This comfortably hosts a database with up to ~5 GB of hot working set in the InnoDB buffer pool. For replicas or larger datasets, scale to a higher plan or add a block storage volume for /var/lib/mysql.Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
Update the package index and apply any pending security updates before adding third-party repositories.
sudo apt update && sudo apt upgrade -yIf the kernel was updated, reboot:
sudo rebootThen reconnect and install the packages you will need for the repository setup and TLS later in the guide:
sudo apt install -y curl gnupg lsb-release ca-certificates opensslStep 2: Add the MariaDB Apt Repository
Ubuntu 24.04 ships MariaDB 10.11 in its default repositories, but the version is frozen for the life of the release. To get current minor versions and the latest stable major (MariaDB 11.4 LTS at time of writing), add the official mariadb.org repository.
MariaDB publishes a setup script that detects your distribution, fetches the correct signing key, and writes an apt source file.
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-11.4"Expected output (abbreviated):
# [info] Checking for script prerequisites.[info] Repository file successfully written to /etc/apt/sources.list.d/mariadb.list
[info] Adding trusted package signing keys...
[info] Successfully added trusted package signing keys
[info] Cleaning package cache...
[info] Running apt-get update...
The script does the following:
noble)/etc/apt/keyrings/mariadb-keyring.pgp/etc/apt/sources.list.d/mariadb.list pointing to deb.mariadb.orgapt-get update so the new packages are immediately availableTo pick a different major version, change --mariadb-server-version. Valid options include mariadb-10.11 (LTS until 2028) and mariadb-11.4 (LTS until 2029). Stick with LTS for production — short-term releases only get 12 months of patches.
Verify the repository is in place:
apt-cache policy mariadb-server | head -10You should see deb.mariadb.org listed ahead of archive.ubuntu.com.
Step 3: Install mariadb-server
Install the server and client packages along with mariadb-backup (the physical backup tool you will configure later).
sudo apt install -y mariadb-server mariadb-client mariadb-backupThe installer creates a mysql system user, lays down the default data directory at /var/lib/mysql, installs a systemd unit, and starts the service.
Verify the installed version:
mariadb --versionExpected output:
mariadb Ver 15.1 Distrib 11.4.4-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2Confirm the service is running:
sudo systemctl status mariadbExpected output:
● mariadb.service - MariaDB 11.4.4 database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-04-16 10:00:00 UTC; 30s ago
Main PID: 4421 (mariadbd)
Status: "Taking your SQL requests now..."
Tasks: 10 (limit: 9498)
Memory: 96.2M
CGroup: /system.slice/mariadb.service
└─4421 /usr/sbin/mariadbdConnect as root over the Unix socket (no password needed yet — Ubuntu configures unix_socket auth for root on fresh installs):
sudo mariadbYou should land at the SQL prompt:
Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 3 Server version: 11.4.4-MariaDB-1:11.4.4+maria~ubu2404 mariadb.org binary distribution
MariaDB [(none)]>
Type exit; to leave. The next step replaces socket-only root auth with a password plus a few other security hardening steps.
Step 4: Run mysql_secure_installation
MariaDB ships a setup script that walks through the standard post-install hardening checklist. Run it now.
sudo mariadb-secure-installationYou will be prompted for each of the following. Recommended answers are shown in brackets.
Enter current password for root (enter for none): [press Enter]
Switch to unix_socket authentication [Y/n]: Y
Change the root password? [Y/n]: Y
New password: [enter a strong 20+ character password]
Re-enter new password: [confirm]
Remove anonymous users? [Y/n]: Y
Disallow root login remotely? [Y/n]: Y
Remove test database and access to it? [Y/n]: Y
Reload privilege tables now? [Y/n]: YWhat each answer does:
- Unix socket auth keeps
sudo mariadbworking on the server itself without a password, which is convenient for automation and backups. - Root password sets a password-based credential used for any non-socket connection (for example,
mariadb -h 127.0.0.1 -u root -p). - Remove anonymous users drops the empty-string user that historically allowed no-password logins.
- Disallow root remotely removes
root@%so the root account cannot be used from other hosts even if a firewall rule leaks. - Remove test database drops the world-writable
testdatabase that ships by default.
Step 5: Tune 50-server.cnf for Production
MariaDB's default configuration is written for a 1 GB laptop from 2005. On any real server you want to raise the buffer pool, set a sensible connection ceiling, and tune the log sizes. Edit the server configuration file:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnfFind the [mysqld] section and apply the settings below. Adjust innodb_buffer_pool_size based on your VPS's total RAM.
[mysqld]
Bind — keep local-only unless app servers are on other machines
bind-address = 127.0.0.1Connections
max_connections = 200
max_allowed_packet = 64M
thread_cache_size = 32InnoDB — the storage engine that matters
innodb_buffer_pool_size = 4G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_io_capacity = 2000
innodb_read_io_threads = 4
innodb_write_io_threads = 4Temp tables
tmp_table_size = 64M
max_heap_table_size = 64MQuery cache — removed in MySQL 8, disabled in MariaDB 10.1.7+
Leave it off. It's a single-threaded bottleneck on modern hardware.
query_cache_type = 0
query_cache_size = 0Slow query log — invaluable for spotting bad queries
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1Character set
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ciSizing the InnoDB Buffer Pool
The buffer pool is where MariaDB caches table data and indexes. It is the single most important setting for performance — almost every read that hits disk instead of the buffer pool is 1,000x slower.
| Total VPS RAM | Recommended innodb_buffer_pool_size |
|---|---|
| 2 GB | 768M |
| 4 GB | 2G |
| 8 GB | 4G |
| 16 GB | 10G |
| 32 GB | 22G |
| 64 GB | 48G |
Why Query Cache Is Removed/Disabled
In MySQL 5.7 the query cache was deprecated because it requires a single global mutex, so every query hitting the cache serializes through that mutex. On a busy multi-core server the cache becomes a bottleneck long before it starts paying for itself. MySQL 8.0 removed it entirely. MariaDB kept the code for compatibility but disabled it by default from 10.1.7 onward. Leave query_cache_type=0 and use the InnoDB buffer pool plus application-layer caching (Redis, Memcached) for hot data.
Save the file (Ctrl+O, Enter, Ctrl+X) and restart MariaDB:
sudo systemctl restart mariadbVerify the new buffer pool size is active:
sudo mariadb -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"Expected output:
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 4294967296 |
+-------------------------+------------+(4294967296 bytes = 4 GB.)
Step 6: Create Users and Databases
Never let applications connect as root. Create a database and a dedicated user with the minimum privileges needed.
Open a MariaDB root session:
sudo mariadbCreate a database using modern character set defaults:
CREATE DATABASE app_production
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Create a user that can only connect from localhost (the most common case for app+db on the same VPS):
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'use-a-strong-password-here';GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES ON app_production.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
If the application runs on a separate server, restrict the user to that IP instead of allowing '%' (any host):
CREATE USER 'app_user'@'10.0.0.42' IDENTIFIED BY 'strong-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_production.*
TO 'app_user'@'10.0.0.42';Verify the grants:
SHOW GRANTS FOR 'app_user'@'localhost';Exit with EXIT; and test the login from the command line:
mariadb -u app_user -p app_productionLeast-Privilege Grant Reference
For reference, here are the common privilege sets:
| Scenario | Grants |
|---|---|
| Typical web app (CRUD + schema migrations) | SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES |
| Read-only reporting user | SELECT |
| Backup user | SELECT, RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, SHOW VIEW, EVENT, TRIGGER |
| Replication user | REPLICATION SLAVE, REPLICATION CLIENT |
| Monitoring (Prometheus mysqld_exporter) | PROCESS, REPLICATION CLIENT, SELECT on performance_schema |
GRANT ALL PRIVILEGES. If an app is compromised, a minimal grant limits the blast radius.Step 7: Enable Binary Logging for Replication
Binary logs record every change to your data in a replayable format. You need them for two things: asynchronous replication (running a read replica, disaster recovery replica, or reporting replica on a separate server) and point-in-time recovery (rolling forward from a full backup to a specific moment in time).
Edit the server config again:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnfAdd the following to the [mysqld] section:
# Binary logging for replication and PITR
server_id = 1
log_bin = /var/log/mysql/mariadb-bin
log_bin_index = /var/log/mysql/mariadb-bin.index
binlog_format = ROW
binlog_row_image = FULL
expire_logs_days = 7
max_binlog_size = 256M
sync_binlog = 1Settings explained:
server_idmust be unique across every server that will participate in replication. Use1for the primary,2+ for replicas.log_binturns on binary logging and sets the file prefix.binlog_format = ROWlogs the actual changed rows, not the SQL statement. This is safer for non-deterministic queries (NOW(),UUID()) and is required for Galera.expire_logs_days = 7automatically purges binlogs older than a week. Match this to your backup cadence — you need binlogs between your most recent full backup and "now" for PITR.sync_binlog = 1fsyncs the binlog on every commit. The safest setting, with a small performance cost that is usually worth paying.
/var/log/mysql exists and is owned by mysql:sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysqlRestart MariaDB:
sudo systemctl restart mariadbVerify binary logging is active:
sudo mariadb -e "SHOW MASTER STATUS;"Expected output:
+--------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000001 | 331 | | |
+--------------------+----------+--------------+------------------+To set up a replica, create a dedicated replication user on the primary, take a consistent backup with mariabackup, restore it on the replica with a different server_id, and run CHANGE MASTER TO pointing at the file and position above. The full replication playbook is beyond the scope of this install guide — the MariaDB Knowledge Base has a complete walkthrough at mariadb.org/documentation.
Step 8: Galera Cluster Introduction
Asynchronous replication (Step 7) gives you a read replica and a disaster recovery copy, but the replica lags the primary by seconds-to-minutes and cannot accept writes. For highly available deployments where every node must be writable, MariaDB ships Galera Cluster — a synchronous multi-master replication plugin.
How Galera works:
- Every node in the cluster is a full read-write replica.
- When a transaction commits on any node, the changeset is certified across all nodes before the commit returns success. If any node would reject the change, the transaction fails everywhere.
- Reads are instant on every node, and writes carry the round-trip cost of cross-node certification (usually sub-millisecond on the same LAN, a few ms across availability zones).
- A cluster of three or more nodes tolerates one node failure without data loss. Five nodes tolerate two. Even numbers are discouraged because they cannot establish a majority quorum cleanly.
50-server.cnf on each node:[galera]
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = "app-cluster"
wsrep_cluster_address = "gcomm://10.0.0.10,10.0.0.11,10.0.0.12"
wsrep_node_address = "10.0.0.10" # unique per node
wsrep_node_name = "node1" # unique per node
wsrep_sst_method = mariabackup
wsrep_sst_auth = "sst_user:sst_password"Galera requires these
binlog_format = ROW
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2Bootstrap the cluster on the first node with galera_new_cluster, then start mariadb normally on nodes 2 and 3. Each new node performs a State Snapshot Transfer (SST) from an existing node using mariabackup and joins the cluster automatically.
Galera is the right choice when you cannot tolerate any write downtime. The trade-offs are increased write latency (bounded by the slowest node) and the operational complexity of managing a cluster. For most single-application VPS deployments, a primary + async replica is simpler and sufficient. Move to Galera when you have traffic or uptime requirements that justify it.
Step 9: Back Up with mariabackup
mariabackup is MariaDB's fork of Percona XtraBackup — a physical backup tool that copies data files while the database is running, without blocking writes on InnoDB tables. It is always the right tool for production backups; mariadb-dump (the renamed mysqldump) produces portable SQL text but locks tables, which is unworkable on a busy database.
Create a backup directory:
sudo mkdir -p /var/backups/mariadb
sudo chown mysql:mysql /var/backups/mariadbCreate a dedicated backup user:
sudo mariadb -e "
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'backup-strong-password';
GRANT SELECT, RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT, SHOW VIEW, EVENT, TRIGGER
ON . TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
"Take a full backup:
sudo mariabackup --backup \
--target-dir=/var/backups/mariadb/full-$(date +%F) \
--user=backup_user \
--password='backup-strong-password'Expected output ends with:
[00] 2026-04-16 10:30:00 completed OK!After the copy, you must run the --prepare phase to make the backup consistent (apply any redo logs captured during the copy):
sudo mariabackup --prepare \
--target-dir=/var/backups/mariadb/full-2026-04-16Now the directory is a ready-to-restore copy of the data files.
Automating Nightly Backups
Create /etc/cron.daily/mariabackup:
#!/bin/bash
set -e
BACKUP_ROOT="/var/backups/mariadb"
TODAY="$BACKUP_ROOT/full-$(date +%F)"mariabackup --backup \
--target-dir="$TODAY" \
--user=backup_user \
--password='backup-strong-password' \
--compress --compress-threads=4
mariabackup --prepare --decompress --target-dir="$TODAY"
Keep last 7 daily backups
find "$BACKUP_ROOT" -maxdepth 1 -type d -name 'full-*' -mtime +7 -exec rm -rf {} \;Make it executable:
sudo chmod +x /etc/cron.daily/mariabackupFor production, copy each nightly backup off-site (rclone to S3, rsync to another VPS) so a server compromise cannot delete both the database and its backups. Pair the full backups with binlog shipping for point-in-time recovery between snapshots.
Restoring
To restore, stop MariaDB, replace /var/lib/mysql with the prepared backup, fix ownership, and start the service:
sudo systemctl stop mariadb
sudo mv /var/lib/mysql /var/lib/mysql.old
sudo mariabackup --copy-back --target-dir=/var/backups/mariadb/full-2026-04-16
sudo chown -R mysql:mysql /var/lib/mysql
sudo systemctl start mariadbStep 10: Enable TLS for Client Connections
Unencrypted database connections leak every query and result over the network. If your application connects over the public internet or across a shared LAN, require TLS.
Generate Certificates
For a self-signed internal CA (fine for app-to-db connections you control on both ends):
sudo mkdir -p /etc/mysql/ssl cd /etc/mysql/sslCA key and cert (10 years)
sudo openssl genrsa 2048 | sudo tee ca-key.pem >/dev/null sudo openssl req -new -x509 -nodes -days 3650 \ -key ca-key.pem -out ca.pem \ -subj "/CN=MariaDB-CA"Server key and cert signed by the CA
sudo openssl req -newkey rsa:2048 -nodes \ -keyout server-key.pem -out server-req.pem \ -subj "/CN=db.example.com" sudo openssl rsa -in server-key.pem -out server-key.pem sudo openssl x509 -req -in server-req.pem -days 3650 \ -CA ca.pem -CAkey ca-key.pem -set_serial 01 \ -out server-cert.pem
sudo chown -R mysql:mysql /etc/mysql/ssl sudo chmod 600 /etc/mysql/ssl/*-key.pem
For public-facing database endpoints, use Let's Encrypt certificates via Certbot on a dedicated subdomain instead of self-signed.
Configure MariaDB to Use TLS
Edit 50-server.cnf and add to the [mysqld] section:
ssl-ca = /etc/mysql/ssl/ca.pem
ssl-cert = /etc/mysql/ssl/server-cert.pem
ssl-key = /etc/mysql/ssl/server-key.pem
tls_version = TLSv1.2,TLSv1.3Reject any client that does not negotiate TLS
require_secure_transport = ONRestart:
sudo systemctl restart mariadbVerify TLS is active on the server side:
sudo mariadb -e "SHOW VARIABLES LIKE '%ssl%';"Expected output shows have_ssl as YES.
Require TLS Per-User
To require TLS from a specific account regardless of the global setting:
ALTER USER 'app_user'@'10.0.0.42' REQUIRE SSL;For mutual TLS (client must also present a certificate signed by your CA):
ALTER USER 'app_user'@'10.0.0.42' REQUIRE X509;Connect with TLS
From the client:
mariadb -h db.example.com -u app_user -p \
--ssl-ca=/etc/mysql/ssl/ca.pem \
--ssl-verify-server-certInside the session, confirm you are on a TLS connection:
SHOW STATUS LIKE 'Ssl_cipher';Expected output:
+---------------+------------------------+
| Variable_name | Value |
+---------------+------------------------+
| Ssl_cipher | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+An empty Value means the connection is unencrypted — fix it before putting the database into production.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
ERROR 2002 (HY000): Can't connect to local MySQL server through socket | MariaDB not running | sudo systemctl status mariadb, check logs with sudo journalctl -u mariadb -n 100 |
ERROR 1045 (28000): Access denied for user 'root'@'localhost' | Password-based root login, but you forgot it | Reset via sudo systemctl stop mariadb && sudo mariadbd --skip-grant-tables --skip-networking &, then ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpw'; |
[ERROR] InnoDB: Cannot allocate memory for the buffer pool | innodb_buffer_pool_size exceeds available RAM | Lower the value to ~50% of total RAM, or add swap |
[Warning] Aborted connection in logs | Application not closing connections cleanly, or wait_timeout too low | Raise wait_timeout to 600, check app connection pool settings |
Replica stuck with Seconds_Behind_Master growing | Slow replica hardware or single-threaded replay | Enable parallel replication: slave_parallel_threads = 4 |
[ERROR] mariadbd: Table './mysql/db' is marked as crashed | Ungraceful shutdown on MyISAM tables | sudo mariadb-check --all-databases --auto-repair, then consider converting to InnoDB |
Too many connections errors | max_connections hit | Raise the limit in 50-server.cnf, and investigate whether the app is leaking connections |
ERROR 1114 (HY000): The table is full in /tmp | tmpfs /tmp too small for a large sort | Point tmpdir in 50-server.cnf to disk-backed storage |
Useful Diagnostic Queries
-- Currently running queries SHOW PROCESSLIST;-- Full engine status (deadlocks, buffer pool stats, pending I/O) SHOW ENGINE INNODB STATUS\G
-- Slow queries summary (if slow_query_log enabled) SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 20;
-- Which tables are hot SELECT table_schema, table_name, rows_read FROM information_schema.table_statistics ORDER BY rows_read DESC LIMIT 20;
FAQ
What is the difference between MariaDB and MySQL?
MariaDB was forked from MySQL in 2009 by its original author after Oracle acquired MySQL through the Sun Microsystems deal. The two projects share a wire protocol and core SQL dialect but have diverged on features: MariaDB ships enterprise-grade features (thread pool, parallel replication, audit logging, hot backups) in its community edition, where MySQL reserves several of those for the commercial Enterprise tier. MariaDB is governed by the non-profit MariaDB Foundation, while MySQL development is controlled by Oracle. For most applications — WordPress, Nextcloud, any ORM-backed web app — the two are drop-in compatible. If you are weighing the switch for an existing MySQL deployment, see our internal MySQL alternative comparison.
How much RAM does MariaDB need?
MariaDB runs on as little as 512 MB for tiny workloads, but production targets are higher. The single most important memory-sizing guideline is the InnoDB buffer pool: allocate 50–70 percent of server RAM to innodb_buffer_pool_size on a dedicated database server, or 25–40 percent on a shared application+database server. A 4 GB VPS comfortably hosts a database with 2–3 GB of hot working set. Beyond the buffer pool, budget another 50–200 MB for connection buffers (scaling with max_connections) and leave enough headroom for the OS file cache.
Does MariaDB still support the query cache?
The query cache was deprecated in MySQL 5.7 and removed entirely in MySQL 8.0. MariaDB kept the code for compatibility but disables it by default from version 10.1.7 onwards. The reason is a single global mutex that serializes every cache lookup, turning the cache into a bottleneck on multi-core hardware long before it pays for itself in cache hits. Leave query_cache_type=0 and rely on the InnoDB buffer pool for in-memory data caching, plus an application-layer cache like Redis or Memcached for materialized results. If you are considering PostgreSQL as an alternative, see our PostgreSQL install guide — Postgres has never had a query cache for the same reasons.
How do I back up a MariaDB database?
Use mariabackup for physical hot backups. It copies InnoDB data files while the database is running, without blocking writes, and can be compressed and streamed directly off the server. For logical backups (SQL dumps portable across major versions and engines), use mariadb-dump (renamed from mysqldump). A production pattern combines the two: nightly mariabackup full backups pushed to S3 or another VPS, with binary logs shipped continuously for point-in-time recovery between snapshots. Retain at least seven days of backups and test restores at least quarterly — an untested backup is not a backup.
Can I run MariaDB and MySQL on the same server?
Not without manually renaming binaries, sockets, and data directories. Both packages install executables named mysqld, bind to port 3306, and expect /var/lib/mysql and /var/run/mysqld/mysqld.sock. For development where you need both, run them in Docker containers with distinct port bindings (3306 for one, 3307 for the other) and separate named volumes. For migrations, stand up the new database on a second VPS and switch your application's connection string once the cutover is ready.
What is Galera Cluster?
Galera is a synchronous multi-master replication plugin bundled with every MariaDB install. In a Galera cluster every node is a full primary — any node accepts reads and writes — and changes are certified across all nodes before a transaction commits. This gives you a highly available database with zero replication lag and automatic failover: a three-node cluster tolerates one node failure with no data loss. The cost is increased write latency (bounded by the slowest node) and the operational overhead of running a cluster. Galera is the right choice when you cannot tolerate any write downtime. For most single-application VPS deployments, a primary plus an async replica is simpler and sufficient.
How do I enable TLS for MariaDB client connections?
Generate a CA, server certificate, and private key with OpenSSL (or use Let's Encrypt for public endpoints), place them under /etc/mysql/ssl, and point ssl-ca, ssl-cert, and ssl-key at them in 50-server.cnf. Add require_secure_transport = ON to reject unencrypted connections globally, or set REQUIRE SSL per-user for fine-grained control. After restart, verify inside a client session with SHOW STATUS LIKE 'Ssl_cipher'; — a cipher name means you are encrypted; an empty value means you are not. For mutual TLS, add REQUIRE X509 to force clients to present a certificate signed by your CA.
Next Steps
Your MariaDB server is installed, secured, tuned, and backed up. Recommended next steps:
- Set up a read replica — Follow the MariaDB Knowledge Base replication guide to add an async replica for read scaling and disaster recovery. Point BI/reporting queries at the replica to offload the primary.
- Install mysqld_exporter + Prometheus + Grafana — Monitor connection counts, slow queries, buffer pool hit rate, and replication lag. See our internal guide on building a monitoring stack for the full setup.
- Compare database engines — If your workload is analytical or you need advanced data types (JSONB, arrays, full-text search), evaluate PostgreSQL. For high-write, document-style data, consider MongoDB. For log and event data, consider ClickHouse.
- Explore the full MariaDB documentation — The official reference at mariadb.org/documentation covers every feature in depth: storage engines, JSON functions, temporal tables, stored procedures, triggers, and the full list of system variables.
- Automate with Ansible — If you manage more than one database server, codify the install + tuning in an Ansible playbook. The
community.mysqlcollection has idempotent modules for users, grants, and replication.
Skip the Manual Install — Deploy a Managed Database VPS>
Our Starter VPS plan gives you the horsepower to run a production MariaDB server with room to grow. Deploy Ubuntu 24.04 in 60 seconds and follow this guide, or use our custom cloud-init template to pre-install MariaDB on first boot.>
- 4 vCPU cores
- 8 GB RAM
- 100 GB NVMe SSD (ideal for /var/lib/mysql)
- Unmetered bandwidth
- Snapshot backups available>
Launch Your Database VPS — Plans start at EUR 7.99/month.