GTID replication replaces brittle file-and-position coordinates with transaction identifiers, which improves replica rebuilds, failovers, and topology changes.
MySQL and MariaDB implement GTID differently, but the core model stays consistent: each committed transaction is assigned a unique identifier, written to the binary log, and tracked by replicas as an executed set. With GTID auto-positioning enabled, the replica requests only the transactions it has not executed, rather than relying on a specific binary log file and byte offset.
Enabling GTID requires binary logging, unique server_id values, and careful initial seeding so the replica’s data matches the source at a known GTID position. Incorrect GTID state during restore can produce duplicate-key errors, missing data, or replication starting from the wrong point, so console access for rollback remains important during first enablement.
Steps to enable GTID replication:
- Choose unique server_id values for the source and replica.
Example: source 101, replica 102.
- Add the required GTID options to the source /mysqld/ configuration file.
Use only the MySQL block or the MariaDB block for a given server.
MySQL config is commonly /etc/mysql/mysql.conf.d/mysqld.cnf on Debian or Ubuntu.
MariaDB config is commonly /etc/mysql/mariadb.conf.d/50-server.cnf on Debian or Ubuntu.
# MySQL (GTID source) [mysqld] server_id = 101 log_bin = mysql-bin binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON
# MariaDB (GTID source) [mysqld] server_id = 101 log_bin = mariadb-bin binlog_format = ROW gtid_domain_id = 1 gtid_strict_mode = ON
A syntax error in /mysqld/ configuration can prevent startup, which can require local console access to revert the change.
- Add the required GTID options to the replica /mysqld/ configuration file.
Use only the MySQL block or the MariaDB block for a given server.
# MySQL (GTID replica) [mysqld] server_id = 102 log_bin = mysql-bin binlog_format = ROW gtid_mode = ON enforce_gtid_consistency = ON log_slave_updates = ON read_only = ON super_read_only = ON relay_log_recovery = ON
# MariaDB (GTID replica) [mysqld] server_id = 102 log_bin = mariadb-bin binlog_format = ROW gtid_domain_id = 1 gtid_strict_mode = ON log_slave_updates = ON read_only = ON
log_slave_updates keeps relay-applied changes in the replica’s binary log, which supports chaining replicas and safer promotions.
- Restart the database service on the source host.
$ sudo docker restart sg-mysql-gtid-primary sg-mysql-gtid-primaryUse the native systemd unit on non-container hosts.
- Restart the database service on the replica host.
$ sudo docker restart sg-mysql-gtid-replica sg-mysql-gtid-replica - Confirm the service is active on the source host.
$ docker ps --filter name=sg-mysql-gtid-primary --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' NAMES IMAGE STATUS sg-mysql-gtid-primary mysql:8.0 Up 16 seconds
- Confirm GTID is enabled on the source.
mysql -u root -p -e "SHOW GLOBAL VARIABLES LIKE 'gtid_mode'; SHOW GLOBAL VARIABLES LIKE 'enforce_gtid_consistency';" +---------------+-------+ | Variable_name | VALUE | +---------------+-------+ | gtid_mode | ON | +---------------+-------+ +--------------------------+-------+ | Variable_name | VALUE | +--------------------------+-------+ | enforce_gtid_consistency | ON | +--------------------------+-------+
Ubuntu often permits
sudo mysqlwhen root uses socket authentication.
- Create a dedicated replication user on the source.
mysql -u root -p -e "CREATE USER 'repl'@'192.0.2.61' IDENTIFIED BY 'ReplPass123!'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'192.0.2.61'; FLUSH PRIVILEGES;"
Use a specific replica IP or subnet instead of '' to reduce exposure.</WRAP> <WRAP tip>Optional TLS enforcement: <code sql>ALTER USER 'repl'@'192.0.2.61' REQUIRE SSL; </code></WRAP> - Record the source //GTID// position for initial seeding. <code sql>mysql -u root -p -e "SELECT @@GLOBAL.gtid_executed\G" *************************** 1. row *************************** @@GLOBAL.gtid_executed: 10df7be4-e136-11f0-9c10-ae1f1ca9c7f8:1-3</code> <WRAP info>//MySQL// restores commonly rely on GTID_PURGED inside the dump, while //MariaDB// restores commonly apply gtid_slave_pos before starting replication.</WRAP> - Create a consistent seed backup on the source. <code bash>mysqldump --all-databases --single-transaction --routines --events --triggers --hex-blob --set-gtid-purged=ON --result-file=/root/sg-work/gtid/seed.sql</code> <WRAP alert>//MyISAM// or other non-transactional tables can break snapshot consistency with //–single-transaction//, which can cause replica drift.</WRAP> - Copy the seed backup file to the replica host. <code bash>$ docker cp sg-mysql-gtid-primary:/root/sg-work/gtid/seed.sql /root/sg-work/gtid/ $ docker cp /root/sg-work/gtid/seed.sql sg-mysql-gtid-replica:/root/sg-work/gtid/seed.sql</code> - Reset replica binary logs before restoring into a reused //MySQL// instance. <code sql>mysql -u root -p -e "RESET MASTER;"</code> <WRAP alert>//RESET MASTER// deletes binary logs on the replica, which removes local recovery history and is unsafe on a server that must retain its binary logs.</WRAP> - Disable //super_read_only// on the replica for the seed import. <code sql>mysql -u root -p -e "SET GLOBAL super_read_only = OFF; SET GLOBAL read_only = OFF;"</code> - Import the seed backup into the replica. <code bash>mysql -u root -p < /root/sg-work/gtid/seed.sql</code> - Re-enable read-only protection on the replica. <code sql>mysql -u root -p -e "SET GLOBAL read_only = ON; SET GLOBAL super_read_only = ON;"</code> - Configure the replica to use //GTID// auto-positioning against the source. <code sql>mysql -u root -p -e "CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.0.2.60', SOURCE_PORT=3306, SOURCE_USER='repl', SOURCE_PASSWORD='ReplPass123!', SOURCE_AUTO_POSITION=1, GET_SOURCE_PUBLIC_KEY=1; START REPLICA;"</code> <WRAP info>Firewall rules must permit TCP 3306 from replica to source.</WRAP> - Verify replication health on the replica. <code sql>mysql -u root -p -e "SHOW REPLICA STATUS\G" *************************** 1. row *************************** Replica_IO_State: Waiting for source to send event Source_Host: 192.0.2.60 Source_User: repl Source_Port: 3306 Replica_IO_Running: Yes Replica_SQL_Running: Yes Auto_Position: 1 Retrieved_Gtid_Set: Executed_Gtid_Set: 10df7be4-e136-11f0-9c10-ae1f1ca9c7f8:1-4 Seconds_Behind_Source: 0 ##### snipped #####</code> <WRAP alert>No%% in IO or SQL running fields usually indicates credentials, network reachability, or binlog/GTID misconfiguration.
- Create a test database on the source.
mysql -u root -p -e "CREATE DATABASE gtid_test;"
- Create a test table on the source.
mysql -u root -p -e "CREATE TABLE gtid_test.ping (id INT PRIMARY KEY AUTO_INCREMENT, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"
- Insert a test row on the source.
mysql -u root -p -e "INSERT INTO gtid_test.ping (id) VALUES (NULL);"
- Query the test row on the replica.
mysql -u root -p -e "SELECT * FROM gtid_test.ping ORDER BY id DESC LIMIT 1;" +----+---------------------+ | id | created | +----+---------------------+ | 1 | 2025-12-25 02:07:38 | +----+---------------------+
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
