WIUNIX ACADEMY
Install MariaDB primary-replica replication with GTID and TLS
Page 3 of 4. 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.
Edit 3 tutorial values
LET’S BUILD
Open the replica SQL session securely
Replica terminal. Use the same history-free interactive method. Retrieve the SAME unique account password used on the primary. Do not place the CHANGE MASTER statement in a shell -e argument or publish its unredacted output/logs.
Replica terminal
sudo env MYSQL_HISTFILE=/dev/null mariadb
Local replica MariaDB administrator prompt is open with client history disabled.
LET’S BUILD
Attach with GTID and verified TLS
Inside replica SQL. MariaDB retains the historical CHANGE MASTER/SLAVE spelling for compatibility. The hostname must match the certificate SAN and private DNS. Replace the password safely before execution. slave_pos starts AFTER the restored snapshot. Verification remains explicitly ON across all supported versions; a TLS error is a stop condition, not permission to disable verification.
Replica SQL
CHANGE MASTER TO
MASTER_HOST='db-primary.example.internal',
MASTER_PORT=3306,
MASTER_USER='academy_repl',
MASTER_PASSWORD='REPLACE_WITH_THE_SAME_UNIQUE_SECRET',
MASTER_USE_GTID=slave_pos,
MASTER_SSL=1,
MASTER_SSL_CA='/etc/mariadb/tls/ca.pem',
MASTER_SSL_VERIFY_SERVER_CERT=1,
MASTER_CONNECT_RETRY=10;
START SLAVE;
SHOW SLAVE STATUS\G
EXIT;
Both receiver and applier run; GTID Slave_Pos, TLS allowed and server certificate verification enabled.
LET’S BUILD
Read receiver AND applier status
Replica Bash. Inspect both Yes flags, zero Last_IO_Errno/Last_SQL_Errno, empty corresponding errors, Using_Gtid Slave_Pos, correct Master_Server_Id101 and both TLS flags Yes. Seconds_Behind_Master0 alone is not proof: NULL can mean a stopped thread, and lag may not reflect queued or idle-source conditions. Protect status/log output because it contains internal topology.
Replica
sudo mariadb -e "SHOW SLAVE STATUS\G"
sudo mariadb -e "SELECT @@server_id,@@read_only,@@GLOBAL.gtid_slave_pos;"
Receiver Yes AND applier Yes, errors0/empty; correct source identity, GTID and verified TLS; read_only1.
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.
LET’S BUILD
Stop replication without deleting data or metadata
Replica only. Record status privately before stopping. Validate the edited option; stop the channel and confirm No/No and retained rows. Do not reset master/replica, delete relay/binlogs, skip transactions or wipe the data directory. This is a reversible operational pause, not a consistency repair. If the primary is still read-only because bootstrap was aborted, release that pause only after deciding it is the sole authoritative writer; the primary release panel is the explicit command.
Replica
(
set -euo pipefail
sudo mariadbd --verbose --help >/dev/null
sudo mariadb -e "SHOW SLAVE STATUS\G; STOP SLAVE; SHOW SLAVE STATUS\G; SELECT * FROM academy_lab.replication_probe ORDER BY id;"
)
No/No threads, original rows/logs/connection metadata retained; read_only remains1.
LET’S BUILD
Resume only from a known consistent position
Optional, after repairing the cause and confirming all needed primary binlogs still exist and data is consistent. Remove only the skip_slave_start line with this editor; keep read_only and all channel settings. If history expired or data drifted, keep this replica paused and build a separately fresh replacement from a new verified seed; do not overwrite its retained data.
Replica
sudo nano /etc/mariadb/mariadb.conf.d/90-academy-replication.cnf
Only skip_slave_start removed after a successful consistency/retention review.