Ubuntu

Configure MariaDB Primary-Replica Replication on Ubuntu 24.04

Primary-replica (historically called master-slave) replication on MariaDB gives you an asynchronous copy of a database you can use for read scaling, analytics queries, hot standby, or rolling maintenance. The setup is three moving parts: bin-log format, a replication user, and a CHANGE MASTER TO call on the replica. This guide walks through the full setup on Ubuntu 24.04 LTS, then shows the equivalent on Debian 13. For a broader sysadmin workflow, our systemctl reference and Rocky 10 post-install tips are good companions.

Original content from computingforgeeks.com - post 2662

Tested April 2026 on Ubuntu 24.04.4 LTS with MariaDB 10.11.14 (the version shipping in noble main)

Step 1: Install MariaDB on both hosts

Run this on both the primary and the replica. Ubuntu 24.04 ships MariaDB 10.11 in the main repository, which is the current LTS of the 10.x series:

sudo apt update
sudo apt install -y mariadb-server mariadb-client
sudo systemctl enable --now mariadb
mariadb --version

Check the version so you can confirm both nodes match:

mariadb  Ver 15.1 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper

Running mixed versions in a replication pair is possible but error-prone. Stick to identical minor versions when you can.

Step 2: Configure the primary for binary logging

Binary logs are the replication stream. Without them, replicas have nothing to pull. Create a drop-in config file under /etc/mysql/mariadb.conf.d/ that enables the bin log, sets the format to ROW (safer than STATEMENT), assigns a unique server ID, and binds MariaDB to all interfaces so the replica can connect:

sudo vi /etc/mysql/mariadb.conf.d/99-replication-primary.cnf

Paste in the primary-side replication config:

[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
bind-address = 0.0.0.0

Create the log directory and set the right owner before restarting, otherwise MariaDB aborts with “File ‘/var/log/mysql/mysql-bin.index’ not found”:

sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysql
sudo systemctl restart mariadb

Confirm the binary log is active. SHOW MASTER STATUS returns the current log filename and byte offset (position). Write these numbers down because the replica needs them in step 4:

sudo mariadb -e "SHOW MASTER STATUS;"

A healthy bin-log setup returns the current log file and byte position:

File	Position	Binlog_Do_DB	Binlog_Ignore_DB
mysql-bin.000001	328

If the command returns an empty result, the bin log isn’t enabled yet. Re-check the drop-in config and the /var/log/mysql ownership.

Step 3: Create a replication user

The replica connects to the primary as a dedicated user with only the REPLICATION SLAVE privilege. Do this on the primary:

sudo mariadb -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;"

Verify the user exists and has the right host pattern:

sudo mariadb -e "SELECT host, user FROM mysql.user WHERE user='repl';"

The replication user shows up with the wildcard host pattern:

Host	User
%	repl

For production, scope the host from % down to the replica’s IP so any other box on the network can’t use the same credentials to read your bin log.

Step 4: Take a consistent snapshot of the primary

The replica needs to start from a point in time that matches a specific binary log position. mariadb-dump with --master-data=2 --single-transaction writes that position into a comment at the top of the dump, and holds a consistent read view for the duration of the export so the data is internally consistent:

sudo mariadb-dump \
  --all-databases \
  --master-data=2 \
  --single-transaction \
  --flush-logs \
  > /tmp/primary-dump.sql

Inspect the head of the dump to find the log file + position the replica should start from:

grep -m1 'CHANGE MASTER' /tmp/primary-dump.sql

Copy the dump to the replica over SSH or your own channel:

scp /tmp/primary-dump.sql replica-host:/tmp/

Step 5: Configure the replica

On the replica, drop in a similar config file with a unique server-id (must be different from the primary) and declare the relay log path:

sudo vi /etc/mysql/mariadb.conf.d/99-replication-replica.cnf

Write in the replica-side config:

[mysqld]
server-id = 2
relay_log = /var/log/mysql/mysql-relay-bin.log
read_only = 1

The read_only = 1 setting stops accidental writes on the replica. Users with SUPER can still write, but ordinary application accounts will get an error if they try to modify data.

sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysql
sudo systemctl restart mariadb

Import the dump to seed the replica’s data:

sudo mariadb < /tmp/primary-dump.sql

Step 6: Point the replica at the primary

The CHANGE MASTER TO call tells the replica where to pull the bin log from, what user to connect as, and which log position to start from. Replace the IP with the primary’s address and the MASTER_LOG_FILE + MASTER_LOG_POS with the values from SHOW MASTER STATUS or from the dump header:

sudo mariadb -e "CHANGE MASTER TO
  MASTER_HOST='10.0.1.50',
  MASTER_USER='repl',
  MASTER_PASSWORD='replpass',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=328;"
sudo mariadb -e "START SLAVE;"

Check the replication state:

sudo mariadb -e "SHOW SLAVE STATUS\G" | grep -E 'Slave_IO_Running|Slave_SQL_Running|Seconds_Behind|Last_Error'

You want both Slave_IO_Running and Slave_SQL_Running set to Yes, Seconds_Behind_Master at 0 or a small positive number, and Last_Error empty. Anything else means the connection isn’t fully healthy and you need to read the last error message to find out what went wrong.

Step 7: Verify end-to-end

On the primary, create a test database and insert a row:

sudo mariadb -e "CREATE DATABASE repltest;
USE repltest;
CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, note VARCHAR(100));
INSERT INTO t1(note) VALUES ('replication works');"

On the replica (a second or two later), check that the database and row replicated over:

sudo mariadb -e "SELECT * FROM repltest.t1;"

The row you inserted on the primary is now visible on the replica:

id	note
1	replication works

If the row doesn’t appear on the replica within a few seconds, check SHOW SLAVE STATUS\G again and look at the Last_SQL_Error and Last_IO_Error fields.

Common failure modes

Error: “Got fatal error 1236 from master when reading data from binary log”

The replica is asking for a log file or position the primary no longer has. Either the primary rotated past the log the replica was following, or the CHANGE MASTER TO call had the wrong position. Re-run the snapshot from Step 4, import it on the replica, and re-point to the new file/position.

Connection refused on port 3306

The primary is bound to localhost only. Re-check the bind-address = 0.0.0.0 line in the primary’s config and restart MariaDB. Also confirm the firewall lets the replica reach port 3306. Our UFW reference shows the syntax for scoping port 3306 to a specific source IP.

Wrap up

Primary-replica replication is the simplest building block for read scaling and hot standby. For something more sophisticated (multi-master, automatic failover, synchronous commits), look at MariaDB Galera Cluster, which our Galera + HAProxy guide walks through. For database monitoring, pair this with the Prometheus MySQL exporter so you can watch replication lag and the bin log position from Grafana. For backups (which you still need even with replication), see our MySQL backup to S3 guide.

Related Articles

Databases Install and Configure OrientDB on Ubuntu 22.04|20.04|18.04 Programming Install Swift Programming Language on Ubuntu 24.04 Ubuntu How To Install Oracle Java on Ubuntu Linux Debian Best Gnome GTK Themes for Kali Linux / Debian / Ubuntu

Leave a Comment

Press ESC to close