Databases

Set Up a MariaDB Galera Cluster on Multiple VPSs

Install MariaDB with the Galera provider on three Linux VPSs, configure wsrep, bootstrap the first node and confirm every node reports Synced.

AdvancedLinux server6 min read

A MariaDB Galera cluster keeps three database nodes in sync, so any node can accept writes and the cluster keeps running when one node goes down. This guide covers a full MariaDB Galera cluster setup on three Linux VPSs: install the packages, write the wsrep configuration, bootstrap the first node, then join the others and check that every node is Synced.

You will work on all three servers. The examples use 203.0.113.10 (node1), 203.0.113.11 (node2) and 203.0.113.12 (node3). Replace them with your own VPS IPs.

Before you start

  • Three Linux VPSs running Ubuntu 22.04/24.04, Debian 12, or AlmaLinux/Rocky 8–9.
  • Root, or a user with sudo.
  • The IP addresses of all three nodes written down, and shell access to each.
  • Working time sync. Galera rejects nodes whose clocks drift, so confirm chrony or systemd-timesyncd is active on every node.
  • Ports 3306 (SQL), 4567 (cluster communication), 4568 (IST) and 4444 (SST) open between the nodes only.

Tip: If your VPSs share a private network, use those addresses for wsrep_cluster_address and keep the public IPs for your applications. Mixing public and private addresses inside one cluster causes connection failures.

Warning: Galera applies cluster writes on every node. Back up anything already stored on these servers, because joining a node runs a State Snapshot Transfer (SST) that overwrites its existing data directory.

Install MariaDB and the Galera provider

Run this on all three nodes.

On Ubuntu and Debian:

Bash
sudo apt update
sudo apt install -y mariadb-server galera-4 rsync

On AlmaLinux and Rocky Linux:

Bash
sudo dnf install -y mariadb-server mariadb-server-galera rsync

Then stop MariaDB so it does not start with a default configuration before you edit the cluster settings:

Bash
sudo systemctl stop mariadb

Find the Galera provider library, since the path differs between distributions:

Bash
ls /usr/lib/galera/libgalera_smm.so /usr/lib64/galera-4/libgalera_smm.so 2>/dev/null

Note the path that exists — you need it in the next step. If neither exists, install the provider package for your distribution and check the MariaDB Galera documentation for your release.

Write the wsrep configuration

On Ubuntu and Debian, create /etc/mysql/mariadb.conf.d/60-galera.cnf. On AlmaLinux and Rocky, create /etc/my.cnf.d/60-galera.cnf. The contents are the same:

INI
[mysqld]
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
innodb_flush_log_at_trx_commit = 0
bind-address = 0.0.0.0

[galera]
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = app_galera
wsrep_cluster_address = gcomm://203.0.113.10,203.0.113.11,203.0.113.12
wsrep_node_name = node1
wsrep_node_address = 203.0.113.10
wsrep_sst_method = rsync

Copy this file to all three nodes and change exactly two lines on node2 and node3:

  • wsrep_node_name — node2, then node3.
  • wsrep_node_address — the node's own IP.

Keep wsrep_cluster_address identical on every node; it lists every member so any node can find the cluster after a restart. If your provider library sits in /usr/lib64/galera-4/, change wsrep_provider to that path.

Open the firewall ports

With firewalld:

Bash
sudo firewall-cmd --permanent --add-port=3306/tcp --add-port=4567/tcp --add-port=4568/tcp --add-port=4444/tcp
sudo firewall-cmd --reload

With ufw, allow the cluster ranges from the other node IPs instead of opening them to the world:

Bash
sudo ufw allow from 203.0.113.10 to any port 4567 proto tcp
sudo ufw allow from 203.0.113.11 to any port 4567 proto tcp
sudo ufw allow from 203.0.113.12 to any port 4567 proto tcp

Repeat for ports 4568 and 4444, and open 3306 only to the application servers that need it.

On AlmaLinux and Rocky, SELinux may block MariaDB from listening on the Galera ports:

Bash
sudo semanage port -a -t mysqld_port_t -p tcp 4567
sudo semanage port -a -t mysqld_port_t -p tcp 4568
sudo semanage port -a -t mysqld_port_t -p tcp 4444

Bootstrap the first node

The first node has to start alone to create the cluster. On node1 only:

Bash
sudo galera_new_cluster

If that command is missing on your distribution, start it this way instead:

Bash
sudo systemctl set-environment MYSQLD_OPTS="--wsrep-new-cluster"
sudo systemctl start mariadb

Confirm node1 is running as a one-node Primary cluster:

Bash
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_size';"

You should see wsrep_cluster_size at 1. If it shows 0, read the error log at /var/log/mysql/error.log (Debian/Ubuntu) or /var/log/mariadb/mariadb.log (RHEL family) before continuing.

Warning: Run the bootstrap command on one node only, and never on a node that is already part of a running cluster. Starting two separate Primaries on the same data set splits the cluster and can leave you with conflicting writes that must be merged by hand.

Join the remaining nodes

On node2 and node3, start MariaDB normally — do not bootstrap:

Bash
sudo systemctl start mariadb

Each node connects to the cluster, requests an SST from an existing member and then reports Synced. The first join copies the whole data set, so it can take a while on a large database. Watch progress with:

Bash
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_local_state_comment';"

Joining, Initialized or Joining, State transfer in progress means the transfer is still running. Synced means the node is live and serving.

Finally, remove the environment override if you set it during bootstrap:

Bash
sudo systemctl unset-environment MYSQLD_OPTS

Check it works: Galera cluster status

On any node, look at the full status set:

Bash
sudo mariadb -e "SHOW STATUS WHERE Variable_name IN ('wsrep_cluster_size','wsrep_cluster_status','wsrep_connected','wsrep_ready','wsrep_local_state_comment','wsrep_incoming_addresses');"

What you want to see on a healthy three-node cluster:

  • wsrep_cluster_size = 3
  • wsrep_cluster_status = Primary
  • wsrep_connected = ON
  • wsrep_ready = ON
  • wsrep_local_state_comment = Synced on every node
  • wsrep_incoming_addresses lists all three IPs

Now prove that writes replicate. On node1:

Bash
sudo mariadb -e "CREATE DATABASE clustertest;"
sudo mariadb -e "CREATE TABLE clustertest.t (id INT PRIMARY KEY, note VARCHAR(50)) ENGINE=InnoDB;"
sudo mariadb -e "INSERT INTO clustertest.t VALUES (1,'from node1');"

On node2 and node3:

Bash
sudo mariadb -e "SELECT * FROM clustertest.t;"

All three must return the same row. Remove the test data when you are done:

Bash
sudo mariadb -e "DROP DATABASE clustertest;"

Troubleshooting

  • MariaDB will not start, log says Failed to open gcomm or cannot open the provider. The wsrep_provider path is wrong for your distribution. Run ls on the usual paths and correct the line in 60-galera.cnf.
  • A joining node sits at Joining for a long time, then fails. Check free disk space, that port 4444 and 4568 are reachable from the donor, and that rsync is installed on both ends. The error log names the failing stage.
  • wsrep_cluster_size is 1 on a node that should have joined. The node started as its own Primary, usually because it was bootstrapped twice or lost contact with the others. Stop it, confirm the firewall and wsrep_cluster_address, then start it again without the bootstrap flag.
  • Error 1045 during SST. You switched wsrep_sst_method to mariabackup without matching wsrep_sst_auth on all nodes. Make the credentials identical everywhere, or go back to rsync.
  • Tables look inconsistent after a restart. Galera only replicates InnoDB. Convert leftover MyISAM tables with ALTER TABLE name ENGINE=InnoDB; and check the error log for warnings about non-transactional writes.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.