Kate works at a MariaDB primary-replica GTID/TLS demonstration display in an illustrative WIUNIX Academy office.

WIUNIX ACADEMY

Install MariaDB primary-replica replication with GTID and TLS

Build a fresh primary and read-only replica, seed a consistent InnoDB dataset, secure the channel with verified TLS and prove that new transactions arrive.

Intermediate70 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 26.04 LTSReviewed 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.

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

THE OUTCOME

What will you have at the end?

A dedicated fresh primary and read-only replica with a consistent seed, verified TLS and demonstrated post-seed transaction delivery.

01Primary101Only writer · InnoDB snapshot + binary logs
02Verified TLSPrivate3306 · restricted replication account
03Replica102Receiver → relay log → applier · read_only
Supported operating systems and versions

Reviewed 2026-10-20. Five OS paths are documented, not full installation tests. Two real MariaDB 10.11.14 instances on Ubuntu 24.04.4 amd64 passed13 focused checks in a private network namespace: consistent dump/restore and snapshot GTID, verified TLS, both threads, real rows, bounded wait/timeout, read-only rejection, restart, missing-CA failure and data-preserving pause. Official APT packages were extracted only. No host install/systemd/UFW/private-DNS/org-PKI renewal/full OS matrix or production migration was tested. Upstream LTS12.3.3 differs from distro11.8/10.11; use matched distro packages. Fictional DEMO photos.

Before you begin

  • Two fresh systemd hosts on the same reviewed OS and MariaDB package version; sudo/SSH, private addresses, synchronized clocks, minimum 2GB RAM each and capacity for database/logs/backups.
  • Existing default-deny private firewall/ACL, verified SSH host keys and internal DNS for db-primary.example.internal. No public3306 access.
  • Existing trusted PKI: primary serverAuth certificate with matching DNS SAN/key and CA chain; public CA chain on replica. Secret manager and protected terminal. No application writer until verification.

One writer, one asynchronous copy

Build a dedicated two-node lab: primary 10.20.0.10 (server_id 101), replica 10.20.0.11 (102), domain 0 on both, TCP 3306 only on the private network. Only the primary accepts application writes. The replica receives binary logs over verified TLS and applies them independently. A commit can be acknowledged before it reaches the replica; this is neither synchronous HA nor a backup. Accidental deletes also replicate.

Agree the boundary before installation

Use two fresh hosts on the SAME selected OS release and identical MariaDB package versions. No existing MySQL/MariaDB installation, user database, replication channel or application writer may be present. This guide seeds only academy_lab on otherwise dedicated instances; it does not migrate a production estate or copy users/system schemas. If any preflight finds existing state, stop and plan a separately backed-up migration. Values are examples: replace private IPs, interface ens18, SSH login dbadmin and certificate DNS names consistently. These private addresses must actually belong to your isolated network.

01

LET’S BUILD

Inspect both fresh hosts

On both hosts, as your existing sudo administrator. The guard aborts on an installed server or retained data/configuration. Do not remove an existing directory to make it pass. Confirm OS, architecture, private addresses, time synchronization and free space; allow at least 2GB RAM and 10GB free for this small lab, plus room for logs, seed and backups.

Bash

Both fresh hosts; Bash as existing sudo administrator.

(
set -euo pipefail
. /etc/os-release
printf '%s %s\n' "$ID" "$VERSION_ID"
dpkg --print-architecture
ip -br address
timedatectl status
df -h / /var
installed=$(dpkg-query -W -f='${binary:Package} ${db:Status-Status}\n')
if printf '%s\n' "$installed" | grep -E '^(mariadb-server|mysql-server)([-:][^ ]*)? installed$' >/dev/null; then
  echo 'Existing database server: STOP' >&2; exit 1
fi
for path in /var/lib/mariadb /var/lib/mysql /etc/mysql/mariadb.conf.d /etc/mariadb/mariadb.conf.d; do
  if sudo test -e "$path"; then echo "Existing state: $path; STOP" >&2; exit 1; fi
done
)
How do I know it worked?

Both hosts are fresh, addresses are assigned, clocks synchronized and resources sufficient.

02

LET’S BUILD

Restrict the primary port before exposing it

Prerequisite: an existing active UFW firewall with default-deny incoming and an already working SSH rule, plus an equivalent upstream private-network ACL. On the primary, permit only the replica source on its real private interface. Do not enable/reset a firewall remotely using this guide. If UFW is not the existing firewall, have its owner install the equivalent source/destination rule before continuing; the commands below are only for active UFW. No inbound database rule is needed on the replica, which binds loopback.

Bash

Primary

(
set -euo pipefail
state=$(sudo env LC_ALL=C ufw status verbose)
printf '%s\n' "$state"
printf '%s\n' "$state" | grep -E '^Status: active$' >/dev/null
printf '%s\n' "$state" | grep -F 'Default: deny (incoming)' >/dev/null
sudo ufw allow in on ens18 from 10.20.0.11 to 10.20.0.10 port 3306 proto tcp
sudo ufw status numbered
)
How do I know it worked?

Active default-deny firewall; only the replica can reach the primary private3306 port.

03

LET’S BUILD

Install this release’s signed packages

On BOTH fresh hosts. APT verifies repository signatures and package hashes; never add another Ubuntu release repository or allow unauthenticated packages. Installation initializes an empty instance and may start it. Initial TCP binding must remain loopback until the private configuration is installed. Compare the exact package versions between hosts.

Ubuntu 26.04: distro MariaDB 11.8, reviewed package patch 11.8.6; install current signed security updates on both hosts, compare exact versions. Configuration include /etc/mysql/mariadb.conf.d. Ubuntu 22.04 is excluded because upstream10.6 community maintenance ended July 2026; Debian 12 has entered LTS and package coverage must be checked. Fresh-install datadir: /var/lib/mariadb; confirmed from official package defaults/maintainer scripts.

Bash

Both fresh hosts; Bash as existing sudo administrator.

(
set -euo pipefail
sudo apt-get update
apt-cache policy mariadb-server mariadb-client
sudo apt-get install -y mariadb-server mariadb-client openssl ca-certificates nano
dpkg-query -W -f='${Package} ${Version}\n' mariadb-server mariadb-client
sudo systemctl enable --now mariadb
sudo mariadb -NBe 'SELECT VERSION();'
sudo ss -lntp 'sport = :3306'
)
How do I know it worked?

Same supported series and exact package version on both hosts; initial3306 is loopback only.

Provide an existing private-CA server certificate

Before the next commands, your PKI administrator must deliver ca.pem, primary-fullchain.pem and primary-key.pem into a root-only academy-pki directory on the primary. The leaf is for serverAuth, valid now, with SAN DNS:db-primary.example.internal and its matching unencrypted service key; the fullchain includes intermediates. Keep the CA signing key offline and out of BOTH database hosts. Deliver the SAME public CA chain as ca.pem on the replica. Certificate issuance/renewal is an existing PKI responsibility, not a self-signed certificate bypass. Verify fingerprints through a trusted channel. Do not proceed with missing, expired or mismatched files.

Explore all tutorials ↗