Incident Response

MySQL Replication Error 1062 and 1032: How to Fix a Broken Replica Safely

Replica_SQL_Running says No, and Last_SQL_Error mentions a duplicate entry or a record that cannot be found. Skipping the event gets replication running in a minute. Whether the replica is still correct afterwards is a different question.

· 11 min read · AG Data Team

MySQL replication error 1062 is a classic reason for a replica to stop: the replica tries to insert a row and finds that a row with the same key is already there. Its twin, error 1032, is the opposite: the source updated or deleted a row that the replica doesn't have. Both look like small, local problems, and both can be "fixed" in seconds by skipping the event. But both mean the same uncomfortable thing: the replica's data had already drifted away from the source before the error appeared.

Step 1: confirm what stopped

Start with SHOW REPLICA STATUS:

SHOW REPLICA STATUS\G
-- look at: Replica_IO_Running, Replica_SQL_Running,
--          Last_SQL_Errno, Last_SQL_Error, Last_SQL_Error_Timestamp

If Replica_IO_Running is Yes and Replica_SQL_Running is No, the replica is still receiving the source's changes but has stopped applying them. That is the situation this article is about. If both threads are running and the replica is simply behind, it is lag rather than breakage; see our guide to MySQL replication lag.

On a multi-threaded replica the useful details live in the replication_applier_status_by_worker table in Performance Schema:

SELECT CHANNEL_NAME, WORKER_ID,
       LAST_ERROR_NUMBER, LAST_ERROR_MESSAGE, LAST_ERROR_TIMESTAMP,
       APPLYING_TRANSACTION
FROM performance_schema.replication_applier_status_by_worker
WHERE LAST_ERROR_NUMBER <> 0;

APPLYING_TRANSACTION gives you the GTID of the transaction the failing worker was applying. Write it down; you will need it.

What 1062 and 1032 actually mean

In the server error reference, 1062 is ER_DUP_ENTRY ("Duplicate entry ... for key ...") and 1032 is ER_KEY_NOT_FOUND ("Can't find record in ..."). On a replica, the source has already committed the transaction successfully. So the transaction itself is fine; the replica's copy of the data is not. Typical ways to get there:

Step 2: look at the transaction before deciding

Find the transaction by its GTID with SHOW RELAYLOG EVENTS on the replica, SHOW BINLOG EVENTS on the source, or mysqlbinlog around the error time. Then compare the affected row on the source and on the replica. The MySQL manual suggests asking three questions before skipping anything:

Step 3: choose the fix

Option A: correct the replica and let the transaction apply. If the replica has a stray row that the source never had (typical for 1062 after a direct write), and the source's version is the correct one, removing or fixing that row on the replica and running START REPLICA lets the original transaction apply cleanly. This is the cleanest outcome, because nothing is skipped. Be careful to make that correction without it being written to the replica's own binary log as a new transaction if this replica may become a source later; plan it with whoever owns the topology.

Option B: skip the transaction with GTIDs. With gtid_mode=ON, you skip a transaction by committing an empty transaction with its GTID. The manual says to stop both replication threads first:

STOP REPLICA;
SET GTID_NEXT = '3e11fa47-71ca-11e1-9e33-c80aa9429562:23';  -- the failing GTID
BEGIN;
COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START REPLICA;

The replica now considers that GTID executed and ignores the real transaction when it arrives. If binary logging is enabled on the replica, that empty transaction stays in its binary log and enters the replication stream if the replica later becomes a source; the manual describes using FLUSH LOGS and PURGE BINARY LOGS to avoid that. The method doesn't apply when ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS is enabled on the channel.

Option C: skip without GTIDs. On position-based replication, sql_replica_skip_counter tells the next START REPLICA to skip events:

STOP REPLICA;
SET GLOBAL sql_replica_skip_counter = 1;
START REPLICA;

It counts events, not transactions, and continues to the end of the event group so it doesn't stop in the middle of one. It cannot be used when gtid_mode=ON, and the next START REPLICA resets it to 0.

Option D: rebuild the replica. If errors keep coming back, or a consistency check shows widespread differences, stop patching. Rebuild the replica from a fresh, consistent backup of the source. That is also a good moment to confirm your backups actually restore; our guide to backup and restore testing covers how.

Skipping fixes replication, not data. After option B or C, the replica is running again but still differs from the source by at least the row that caused the error, plus the skipped transaction itself. Treat a skip as a temporary measure and schedule a consistency check.

Two settings to leave alone

After the fix: check consistency and prevent the next one

Key takeaways

MySQL Replication GTID Incident Response
Work with us

Replica stopped and you are not sure it is safe to skip?

We diagnose broken MySQL and MariaDB replication, bring replicas back in sync and set up the checks that catch drift early. First response to critical incidents within 15 minutes, 24/7.

Get in touch More from the blog