Logo

MariaDB Galera Cluster: synchronous multi-master

MariaDB Galera Cluster: synchronous multi-master

Build a 3-node multi-master MariaDB cluster with Galera: synchronous replication, write to any node, automatic failover. The standard solution for MariaDB / MySQL HA.

Introduction

Galera Cluster is a MariaDB/MySQL extension for synchronous multi-master replication:

  • All writes propagated synchronously to other nodes
  • Write to any node
  • Automatic failover (every node is "primary")
  • Strong consistency (no eventual reads)
  • Minimum 3 nodes recommended (avoid split-brain)

Limits:

  • All tables must be InnoDB (no MyISAM, no TokuDB)
  • LARGE transactions can be rejected (size / lock contention)
  • Write latency = network latency between nodes

Use cases: write-heavy LAMP apps (high-traffic WordPress, e-commerce, SaaS).

Prerequisites

  • 3 Linux VPS Debian / Ubuntu
  • Private network between VPS
  • IPs: 10.0.0.1, 10.0.0.2, 10.0.0.3
  • Root access on each

Step 1: Install MariaDB on all 3 nodes

sudo apt update
sudo apt install -y mariadb-server mariadb-client galera-4
mariadb --version

Step 2: Firewall

Galera ports:

  • 3306: MariaDB SQL
  • 4567: Galera replication (TCP + UDP)
  • 4568: IST (Incremental State Transfer)
  • 4444: SST (State Snapshot Transfer)

On each node:

sudo ufw allow from 10.0.0.0/24 to any port 3306
sudo ufw allow from 10.0.0.0/24 to any port 4567 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 4567 proto udp
sudo ufw allow from 10.0.0.0/24 to any port 4568
sudo ufw allow from 10.0.0.0/24 to any port 4444

Step 3: Stop MariaDB everywhere

sudo systemctl stop mariadb

Step 4: Configure Galera

On each node, create /etc/mysql/mariadb.conf.d/60-galera.cnf:

[mysqld]
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=2
innodb_buffer_pool_size=2G

bind-address=0.0.0.0

wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="my_cluster"
wsrep_cluster_address="gcomm://10.0.0.1,10.0.0.2,10.0.0.3"
wsrep_sst_method=mariabackup
wsrep_sst_auth=sstuser:strong-sst-pass

# Node-specific: replace with node IP
wsrep_node_address="10.0.0.1"
wsrep_node_name="node1"

⚠️ On node2: wsrep_node_address="10.0.0.2", wsrep_node_name="node2". Same for node3.

Step 5: Create SST user

On node1 only, start in normal mode first:

sudo systemctl start mariadb
sudo mariadb
CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'strong-sst-pass';
GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';
FLUSH PRIVILEGES;
sudo systemctl stop mariadb

Step 6: Bootstrap the cluster

On node1:

sudo galera_new_cluster

This starts MariaDB and initializes the cluster.

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

Should show 1.

Step 7: Start node2 and node3

On node2:

sudo systemctl start mariadb

Wait. Node copies database from node1 (SST via mariabackup).

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

Should show 2.

Same on node3:

sudo systemctl start mariadb
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_size';"

Should show 3.

Step 8: Verify replication

On node1:

CREATE DATABASE test;
USE test;
CREATE TABLE foo (id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(100));
INSERT INTO foo (msg) VALUES ('Hello from node1');

On node2 and node3:

USE test;
SELECT * FROM foo;

Data present everywhere, real-time.

Write on node2:

INSERT INTO foo (msg) VALUES ('Hello from node2');
SELECT * FROM foo;

All writes visible on all 3 nodes.

Step 9: Detailed status

SHOW STATUS LIKE 'wsrep_%';

Important variables:

  • wsrep_cluster_size: nodes UP
  • wsrep_cluster_status: Primary (OK) / non-Primary (split-brain)
  • wsrep_connected: ON
  • wsrep_ready: ON
  • wsrep_local_state_comment: Synced (OK)

Step 10: Failover

Stop a node:

sudo systemctl stop mariadb

On others:

SHOW STATUS LIKE 'wsrep_cluster_size';   -- 2

Cluster still works. Writes continue. On restart, downed node auto-catches up (IST if few changes, SST otherwise).

⚠️ If you lose 2 of 3 nodes, the remaining one goes non-Primary (writes refused) to avoid split-brain. Force bootstrap:

sudo mariadb -e "SET GLOBAL wsrep_provider_options='pc.bootstrap=YES';"

Step 11: Load balancer in front

/etc/haproxy/haproxy.cfg:

frontend galera_front
    bind *:3306
    mode tcp
    default_backend galera_back

backend galera_back
    mode tcp
    balance leastconn
    option httpchk
    server node1 10.0.0.1:3306 check port 9200 inter 2s
    server node2 10.0.0.2:3306 check port 9200 inter 2s
    server node3 10.0.0.3:3306 check port 9200 inter 2s

For HTTP healthcheck, install xinetd + clustercheck on each node.

Step 12: Backups

Classic MariaDB backups work on Galera. Backup from one specific node (e.g. node3) to avoid loading write nodes.

sudo mariadb-backup --backup --target-dir=/var/backups/mariadb-$(date +%F) --user=root

Or mysqldump:

sudo mysqldump --all-databases --single-transaction | gzip > /var/backups/all-$(date +%F).sql.gz

Troubleshooting

"WSREP: Failed to open channel"

Network blocked:

nc -zv 10.0.0.2 4567
nc -zv 10.0.0.2 4444

SST fails

Check sstuser credentials and that mariabackup is installed everywhere:

sudo apt install -y mariadb-backup

Split-brain (non-Primary)

Cluster lost quorum. If majority down, restore nodes or force bootstrap on the most up-to-date one:

SHOW STATUS LIKE 'wsrep_last_committed';

Node with highest value is most up-to-date.

Degraded performance

Galera adds latency (sync). Group small transactions. Set innodb_flush_log_at_trx_commit=2 (less safe but faster).

Useful commands

sudo mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_local_state_comment';"
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_%';"

sudo galera_new_cluster
sudo systemctl start mariadb

sudo tail -f /var/log/mysql/error.log

sudo ss -tunlp | grep -E '3306|4444|4567|4568'

Conclusion

Galera Cluster provides:

  • Synchronous multi-master
  • Automatic failover
  • Distributed reads and writes

Limits:

  • Write latency = inter-node network
  • InnoDB tables only
  • 3 nodes min to avoid split-brain

Going further:

  • Use HAProxy or ProxySQL in front for single endpoint
  • Combine with MaxScale for intelligent routing
  • For multi-DC, check Galera segments docs

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members