WIUNIX ACADEMY
Install MariaDB primary-replica replication with GTID and TLS
Page 5 of 6. Review the earlier steps and prerequisites before continuing.
YOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
USE YOUR OWN VALUES
Configure this tutorial
Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.
Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.
Set values for my environment3 editable values
Illustrative status excerpt
Sample output only, not a command and not a promise about your server. Real file names, positions, delays and TLS details vary.
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_IO_Errno: 0
Last_SQL_Errno: 0
Using_Gtid: Slave_Pos
Master_Server_Id: 101
Master_SSL_Allowed: Yes
Master_SSL_Verify_Server_Cert: Yes
Seconds_Behind_Master: 0LET’S BUILD
Release the primary and commit a new row
Primary only. First confirm replica status and the restored seed row. This releases the bootstrap write pause and commits a new row AFTER the snapshot. Save the returned non-secret GTID; the next replica panel waits for this exact position. Keep application routing on the primary.
Primary
sudo mariadb -e "SET GLOBAL read_only=OFF; INSERT INTO academy_lab.replication_probe VALUES (2,'after-seed'); SELECT @@GLOBAL.gtid_binlog_pos AS target_gtid; SELECT * FROM academy_lab.replication_probe ORDER BY id;"
Primary read_only0; rows1 and2; record the actual target_gtid returned by this commit.
LET’S BUILD
Wait for the commit and compare actual data
Inside a new replica SQL session opened with the earlier terminal panel. Replace the GTID placeholder with the exact primary output, not the sample shown in any article. MASTER_GTID_WAIT returns a non-negative value on success, -1 on timeout or NULL on error. Any -1/NULL is a failure: do not proceed based only on a zero lag field. Compare BOTH rows and their text with the primary. This probes the small table; it is not a checksum of every production object.
Replica SQL
SELECT MASTER_GTID_WAIT('REPLACE_WITH_ACTUAL_TARGET_GTID',30) AS wait_result;
SELECT id,note FROM academy_lab.replication_probe ORDER BY id;
SHOW SLAVE STATUS\G
EXIT;
Wait is non-negative, rows exactly1 consistent-seed /2 after-seed, receiver/applier both Yes with no error.
LET’S BUILD
Check restart recovery without changing roles
Optional planned disruption on the replica ONLY after the row checks. Restart briefly interrupts reads and replication; the configured channel normally starts automatically because skip_slave_start is not set. Confirm both threads, retained GTID/data and read_only again. If replication is stopped by an intentional operational policy, diagnose before explicitly starting it; restarting cannot fix missing logs or drift.
Replica
sudo systemctl restart mariadb
systemctl is-active mariadb
sudo mariadb -e "SHOW SLAVE STATUS\G; SELECT @@read_only,@@GLOBAL.gtid_slave_pos; SELECT * FROM academy_lab.replication_probe ORDER BY id;"
Same two rows and persisted position; read_only1; receiver/applier recover with zero errors.
LET’S BUILD
Keep a separate recoverable backup
On the primary after the verification window; no concurrent schema change/nontransactional writes. This backs up the lab schema and its selected OS configuration/TLS with original directory structure, checks hashes and compares the archive to disk. It retains original data and prior backups and aborts on any failure. The archive contains a private service key: keep it encrypted in approved off-host storage. Hash/read-back checks are not a restore test. Before relying on it or retiring anything, restore the SQL into a separate isolated fresh MariaDB instance with matching versions and verify schemas/rows; never import a recovery dump on a live writer. Plan separate account/system-object backups for a real deployment.
Primary
sudo bash -eu <<'BACKUP'
umask 077
install -d -m 0700 /root/academy-backups
backup=$(mktemp -d /root/academy-backups/mariadb-XXXXXXXX)
mariadb-dump --single-transaction --quick --routines --events --triggers --databases academy_lab > "$backup/academy_lab.sql"
test -s "$backup/academy_lab.sql"
tar -C / -cpf "$backup/config-tls.tar" etc/mariadb/mariadb.conf.d/90-academy-replication.cnf etc/mariadb/tls
cd "$backup"
sha256sum academy_lab.sql config-tls.tar > SHA256SUMS
sha256sum -c SHA256SUMS
tar -tf config-tls.tar >/dev/null
tar -C / -df config-tls.tar
printf 'Retained backup: %s\n' "$backup"
BACKUP
Dump/archive read-back pass; originals retained. Acceptance still requires an isolated restore rehearsal and protected off-host copy.
LET’S BUILD
Make an intentional pause survive restart
For a rollback/pause, stop directing reads to the replica and keep all writes on the healthy primary. Do not promote either server. On the replica open its own configuration and ADD the next setting within the existing mariadb group, leaving read_only ON. This persistent skip is necessary because STOP SLAVE alone does not survive a service restart.
Replica
sudo nano /etc/mariadb/mariadb.conf.d/90-academy-replication.cnf
Replica configuration opened for the single persistent-pause addition.
LET’S BUILD
Persistent pause option
File addition only, inside the existing mariadb section on the replica. Do not replace the rest of the file.
File contents; save in named file, not a shell.
skip_slave_start=ON
One skip_slave_start line is saved within the existing mariadb group; read_only remains ON.