← Start of tutorial

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.

Ubuntu 26.10Reviewed against official documentation ·

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
20

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.

Bash

Replica terminal

sudo env MYSQL_HISTFILE=/dev/null mariadb
How do I know it worked?

Local replica MariaDB administrator prompt is open with client history disabled.

21

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.

SQL

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;
How do I know it worked?

Both receiver and applier run; GTID Slave_Pos, TLS allowed and server certificate verification enabled.

22

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.

Bash

Replica

sudo mariadb -e "SHOW SLAVE STATUS\G"
sudo mariadb -e "SELECT @@server_id,@@read_only,@@GLOBAL.gtid_slave_pos;"
How do I know it worked?

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.

EXAMPLE OUTPUT
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: 0
23

LET’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.

Bash

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;"
How do I know it worked?

Primary read_only0; rows1 and2; record the actual target_gtid returned by this commit.

24

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.

SQL

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;
How do I know it worked?

Wait is non-negative, rows exactly1 consistent-seed /2 after-seed, receiver/applier both Yes with no error.

25

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.

Bash

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;"
How do I know it worked?

Same two rows and persisted position; read_only1; receiver/applier recover with zero errors.

26

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.

Bash

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
How do I know it worked?

Dump/archive read-back pass; originals retained. Acceptance still requires an isolated restore rehearsal and protected off-host copy.

27

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.

Bash

Replica

sudo nano /etc/mariadb/mariadb.conf.d/90-academy-replication.cnf
How do I know it worked?

Replica configuration opened for the single persistent-pause addition.

28

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.

INI · /etc/mariadb/mariadb.conf.d/90-academy-replication.cnf

File contents; save in named file, not a shell.

skip_slave_start=ON
How do I know it worked?

One skip_slave_start line is saved within the existing mariadb group; read_only remains ON.

29

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.

Bash

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;"
)
How do I know it worked?

No/No threads, original rows/logs/connection metadata retained; read_only remains1.

30

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.

Bash

Replica

sudo nano /etc/mariadb/mariadb.conf.d/90-academy-replication.cnf
How do I know it worked?

Only skip_slave_start removed after a successful consistency/retention review.

Explore all tutorials ↗