Chapter 15 · Galera Cluster: Synchronous Multi-Primary Replication and High Availability

Galera Security, TLS, Rolling Maintenance, Upgrades, Failure Injection, and Recovery

Secure MariaDB Galera client, replication, and SST traffic; operate one-node-at-a-time maintenance with compatibility gates; inject failures; and recover a full cluster only from proven authoritative state.

Advanced165–210 minutesTLS + maintenance + failure-recovery labMariaDB Community 12.3.2 + Galera 4 baselineCurriculum anchor: 11.8 LTS · verify server/provider/SST versionsLinux nodes/containers · Last reviewed: August 2026

Learning outcomes

A three-node cluster that survives failures but sends replication and State Snapshot Transfer data in clear text, runs untested rolling upgrades, or has no full-outage recovery drill is not production-ready. This lesson turns the previous four mechanisms into an operating procedure: secure every traffic plane, change one node at a time, verify provider/server compatibility, inject failures, and recover only from proven authoritative state.

01

Distinguish client TLS, Galera replication TLS, and SST transport security as separate channels.

02

Configure the Community-compatible wsrep provider TLS pattern and explain certificate/CA ownership and restart requirements.

03

Plan rolling maintenance with drain, stop, upgrade/change, rejoin, state-transfer, and return-to-service gates.

04

Inject node failures safely and verify quorum/data convergence rather than only process restarts.

05

Execute a full-cluster recovery decision tree using grastate.dat/safe_to_bootstrap/wsrep-recover evidence and tested backups.

Version/product discipline

MariaDB exposes both Community Galera security mechanisms and additional Enterprise Cluster TLS/automation features. This lesson uses the provider-level socket.ssl_* configuration documented for Galera because it is broadly applicable. Variables/modes documented specifically for MariaDB Enterprise Cluster must not be assumed to exist or behave identically on Community Server. Verify the exact server and provider versions before rolling changes.

1. Start with a clean cluster and record the compatibility packet

yaml · compose.yaml
services:  n1:    image: mariadb:12.3.2    container_name: mdb15-n1    environment:      MARIADB_ROOT_PASSWORD: labroot    command:      - --bind-address=0.0.0.0      - --binlog-format=ROW      - --default-storage-engine=InnoDB      - --innodb-autoinc-lock-mode=2      - --wsrep-on=ON      - --wsrep-provider=/usr/lib/galera/libgalera_smm.so      - --wsrep-cluster-name=servicehub15      - --wsrep-cluster-address=gcomm://n2,n3      - --wsrep-node-name=n1      - --wsrep-sst-method=rsync      - --wsrep-new-cluster    ports:      - "33151:3306"  n2:    image: mariadb:12.3.2    container_name: mdb15-n2    environment:      MARIADB_ROOT_PASSWORD: labroot    command:      - --bind-address=0.0.0.0      - --binlog-format=ROW      - --default-storage-engine=InnoDB      - --innodb-autoinc-lock-mode=2      - --wsrep-on=ON      - --wsrep-provider=/usr/lib/galera/libgalera_smm.so      - --wsrep-cluster-name=servicehub15      - --wsrep-cluster-address=gcomm://n1      - --wsrep-node-name=n2      - --wsrep-sst-method=rsync    ports:      - "33152:3306"  n3:    image: mariadb:12.3.2    container_name: mdb15-n3    environment:      MARIADB_ROOT_PASSWORD: labroot    command:      - --bind-address=0.0.0.0      - --binlog-format=ROW      - --default-storage-engine=InnoDB      - --innodb-autoinc-lock-mode=2      - --wsrep-on=ON      - --wsrep-provider=/usr/lib/galera/libgalera_smm.so      - --wsrep-cluster-name=servicehub15      - --wsrep-cluster-address=gcomm://n1      - --wsrep-node-name=n3      - --wsrep-sst-method=rsync    ports:      - "33153:3306"
shell · bootstrap then join
docker compose down -v --remove-orphans# Bootstrap exactly one node for a brand-new disposable cluster.docker compose up -d n1# Wait until n1 reports wsrep_ready=ON, then join the other nodes.docker compose up -d n2 n3# Verify all three nodes before creating application data.docker exec mdb15-n1 mariadb -uroot -plabroot -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_size'; SHOW GLOBAL STATUS LIKE 'wsrep_cluster_status';"docker exec mdb15-n2 mariadb -uroot -plabroot -e "SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';"docker exec mdb15-n3 mariadb -uroot -plabroot -e "SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';"
sql · all nodes — record server/provider/protocol identity
SELECT VERSION() AS server_version;SHOW GLOBAL STATUS WHERE Variable_name IN ('wsrep_provider_name','wsrep_provider_version','wsrep_protocol_version','wsrep_cluster_state_uuid','wsrep_cluster_status','wsrep_local_state_comment');SHOW GLOBAL VARIABLES WHERE Variable_name IN ('wsrep_provider','wsrep_sst_method','wsrep_cluster_name');

Store this packet with the maintenance change. “Same MariaDB major version” is not enough when Galera provider, SST tool, package source, operating system, or schema-upgrade path can differ.

2. Three traffic planes need three security stories

Traffic Typical port/path Security control
application → MariaDB 3306/TCP server/client TLS, certificate/hostname verification, account grants
Galera replication/group communication 4567 TCP/UDP by default wsrep provider TLS + private network/firewall
IST 4568/TCP by default provider/state-transfer protections + network controls
SST 4444/TCP by default SST-method-specific TLS/authentication

Encrypting client connections does not encrypt inter-node write sets. Encrypting wsrep replication does not automatically secure an rsync/mariabackup SST. Treat each plane independently and verify it.

3. Provider-level TLS pattern for Community Galera

Galera provider TLS uses wsrep_provider_options such as socket.ssl_ca, socket.ssl_cert, and socket.ssl_key. The certificate authority (CA) establishes trust; each node should have a private key protected by operating-system permissions and a certificate appropriate for the identities you validate.

ini · galera.cnf — provider TLS pattern
[mariadb]ssl_ca=/etc/mysql/tls/ca.pemssl_cert=/etc/mysql/tls/node.pemssl_key=/etc/mysql/tls/node-key.pemwsrep_provider_options="socket.ssl=true;socket.ssl_ca=/etc/mysql/tls/ca.pem;socket.ssl_cert=/etc/mysql/tls/node.pem;socket.ssl_key=/etc/mysql/tls/node-key.pem"

These provider options are not dynamic in the ordinary case, so plan controlled restarts. Some versions/products support rolling TLS-transition mechanisms; verify exact documentation instead of assuming a mixed encrypted/unencrypted cluster will interoperate safely.

Identity matters

TLS that merely encrypts bytes without validating the expected peer certificate/CA leaves a different risk than verified identity. For client connections, use the connector's verification mode and hostname/SAN validation. For Galera/SST, follow the exact provider/SST-mode capabilities of your target version.

4. Secure SST explicitly

The lab used rsync for simplicity. MariaDB documents method-specific SST security: mariabackup can use TLS settings and needs donor-side backup authentication/privileges in Community-style manual setups; rsync commonly relies on an external secure transport such as stunnel when encryption is required.

Before production, answer four questions: Which SST method is used on every node? What credentials/privileges does it need? Is transfer encrypted and authenticated? What happens to donor availability during the transfer?

sql · verify SST settings on every node
SHOW GLOBAL VARIABLES WHERE Variable_name IN ('wsrep_sst_method','wsrep_sst_auth','wsrep_sst_donor');

Never print real wsrep_sst_auth secrets into tickets or screenshots. Prefer secret files/socket authentication/automatic mechanisms only when your exact supported product version documents them.

5. Rolling maintenance runbook

One-node-at-a-time maintenance preserves quorum in a three-node cluster, but only if the remaining two nodes are healthy and sized for the workload.

Gate Action Acceptance evidence
precheck verify all 3 Synced, backups current, no flow-control crisis status packet + backup restore evidence
drain remove n3 from client routing no new app connections to n3
stop/change stop n3; patch/configure one supported change n1+n2 remain Primary size 2
rejoin start n3 normally, never bootstrap IST/SST completes; n3 Synced/ready
validate application smoke test + wsrep metrics/logs same cluster UUID, expected provider/version
return restore routing health gate passes under traffic

Repeat for the next node only after the previous one is fully returned. Major-version upgrades require explicit release documentation; SST methods can have cross-major backup/redo compatibility constraints. A “rolling restart worked in staging” does not prove a rolling major upgrade is supported.

6. Safe node-failure injection

Kill n3 abruptly rather than stopping it gracefully. n1+n2 should retain quorum. Continue a small write, then restart n3 and require state convergence.

shell · inject one-node crash
docker kill mdb15-n3docker exec mdb15-n1 mariadb -uroot -plabroot -e "SHOW GLOBAL STATUS WHERE Variable_name IN ('wsrep_cluster_status','wsrep_cluster_size');"
sql · n1 — prove majority still accepts replicated work
INSERT INTO servicehub_galera_lab.tickets(customer_id,state,priority) VALUES (801,'open',3);
shell · restart failed node and inspect transfer
docker start mdb15-n3docker logs --since 2m mdb15-n3 2>&1 | grep -Ei "IST|SST|Synced|ready" || true
sql · n3 — data convergence check
SHOW GLOBAL STATUS WHERE Variable_name IN ('wsrep_cluster_status','wsrep_cluster_size','wsrep_ready','wsrep_local_state_comment');SELECT COUNT(*) FROM servicehub_galera_lab.tickets WHERE customer_id=801;

7. Full-cluster failure: this is where runbooks matter

To practice safely, first ensure no external clients use the lab, then stop all nodes. After graceful shutdown, inspect grastate.dat and choose the node marked safe to bootstrap. After a hard crash, use --wsrep-recover to compare recovered positions.

shell · graceful full stop and saved-state inspection
docker stop mdb15-n3 mdb15-n2 mdb15-n1docker exec mdb15-n1 cat /var/lib/mysql/grastate.datdocker exec mdb15-n2 cat /var/lib/mysql/grastate.datdocker exec mdb15-n3 cat /var/lib/mysql/grastate.dat
Do not automate “node1 always bootstraps.”

The correct bootstrap source is the most advanced authoritative state. Hostname order is irrelevant. If the saved state is uncertain, recover each node's position, compare it, preserve forensic evidence, and consult the tested recovery procedure before creating a new Primary Component.

8. Wrong recovery: bootstrap stale state, then let newer nodes join

This shortcut can discard acknowledged history. Galera will treat the newly bootstrapped component as authoritative; a later node does not arrive as a competing truth source that automatically merges missing commits. The repair for an uncertain split/divergence is an incident: stop writes, identify accepted histories, restore/reconcile from backups/binlogs/business records as appropriate, and rebuild clean nodes.

This is also why Chapter 13 remains mandatory. Galera reduces some node-loss scenarios; it does not provide historical recovery from operator error, malware, logical corruption, or a bad bootstrap decision.

9. Security and maintenance evidence checklist

  • Server version, package source, wsrep_provider_version, protocol version, SST tool/version recorded.
  • Private cluster network/firewall restricts 4567/4568/4444 to intended members; wsrep_allowlist considered where supported.
  • Client TLS and connector identity verification tested independently from inter-node TLS.
  • Provider/SST certificates have ownership, rotation dates, monitoring, and rollback procedure.
  • Backups are encrypted/off-site as required and restore-tested; cluster nodes are not counted as backup copies.
  • Rolling change rehearsed with one node out and remaining quorum/capacity measured.
  • Full outage bootstrap runbook names evidence/decision owner, not a permanently privileged “bootstrap node.”

10. Production judgment and bridge to Chapter 16

Operate Galera as a distributed system: compatibility, certificates, membership, flow control, state transfer, backups, and client routing all have owners and observable acceptance criteria. A safe maintenance window is not merely “restart nodes one at a time”; it is drain → prove quorum → change → rejoin → validate → return.

Chapter 16 moves from cluster availability to large-table lifecycle. Partitioning and online DDL can still create cluster-wide consequences: metadata operations, write-set volume, SST risk, and maintenance windows must be evaluated against the Galera topology you now understand.

Check your understanding

  1. Why are client TLS, wsrep replication TLS, and SST TLS separate controls?
  2. What should be recorded before a rolling Galera change?
  3. Why must a node rejoin normally after maintenance rather than use --wsrep-new-cluster?
  4. How do you select the bootstrap node after a full outage?
  5. Why does a three-node Galera cluster still require Chapter 13 backups?
Review the answers

The three traffic planes use different protocols/options and securing one does not secure the others. Record server/provider/SST versions, cluster state, backups, capacity, and rollback gates before maintenance. A normal rejoin preserves the existing cluster identity; --wsrep-new-cluster declares a new authority. After a full outage, select the most advanced safe state using grastate/safe_to_bootstrap and, when needed, wsrep recovery evidence. Galera replicates current state and mistakes; backups provide historical/off-site recovery that cluster membership cannot.

shell · final cleanup
docker compose down -v --remove-orphans

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.