说明:下文命令同时给出 MySQL 5.7 传统语法与 MySQL 8.0.23+ 新语法(
REPLICA/SOURCE),执行时按实际版本选择其一。所有"跳过事务"操作都只适用于确认该事务数据可以丢弃的场景,生产环境务必先评估数据一致性。
一、先理解原理:报错为什么会产生
1.1 复制三线程模型
| 线程 | 所在节点 | 职责 | 对应状态字段 |
|---|---|---|---|
| Binlog Dump Thread | 主库 | 读取 binlog,按位点/GTID 推送给从库 | --- |
| I/O Thread | 从库 | 连接主库、接收 binlog 事件、写入本地 relay log | Slave_IO_Running / Replica_IO_Running |
| SQL Thread(或 Worker) | 从库 | 读取 relay log 并回放(应用)到从库数据文件 | Slave_SQL_Running / Replica_SQL_Running |
复制链路:
主库写事务 → binlog → dump线程发送 → 从库IO线程写 relay log
→ SQL线程/Worker 回放 relay log → 从库数据
1.2 由此可推出两类故障边界
- IO 线程报错(Last_IO_Errno):连接、认证、网络、主库 binlog 不存在、relay log 写入失败。
- SQL 线程报错(Last_SQL_Errno):回放时数据冲突、对象不存在、锁冲突、relay log 损坏。
这是排查的第一分叉点:先看是 IO 错还是 SQL 错。
1.3 位点模式与 GTID 模式
- 位点模式:以
Master_Log_File + Read_Master_Log_Pos定位,跳过错误靠SQL_SLAVE_SKIP_COUNTER。 - GTID 模式:以
gtid_executed集合定位,事务全局唯一编号。GTID 模式不支持sql_slave_skip_counter,跳过必须"注入空事务"。
二、通用定位五步(任何报错先做这五条)
sql
-- 1. 看复制全貌:错误号、错误信息、线程状态、位点、GTID差集
SHOW SLAVE STATUS\G
-- MySQL 8.0.22+ 亦可
SHOW REPLICA STATUS\G
-- 2. 精确定位失败事务(含 worker 级错误)
SELECT * FROM performance_schema.replication_applier_status_by_worker
WHERE LAST_ERROR_NUMBER <> 0\G
-- 3. 看连接与线程状态
SELECT * FROM performance_schema.replication_connection_status\G
SHOW PROCESSLIST;
-- 4. 主库当前位点/GTID
SHOW MASTER STATUS\G
-- 5. 解析具体事件内容
-- 在主库或从库执行:
mysqlbinlog --base64-output=DECODE-ROWS -vv mysql-bin.000003 \
--start-position=196 --stop-position=440
关键字段判读:
| 字段 | 含义 |
|---|---|
Last_IO_Errno/Last_IO_Error |
IO 线程最后错误(连接类) |
Last_SQL_Errno/Last_SQL_Error |
SQL 线程最后错误(回放类) |
Slave_IO_Running |
Yes / No / Connecting |
Slave_SQL_Running |
Yes / No |
Seconds_Behind_Master |
延迟秒数,NULL 通常表示 SQL 线程已停 |
Retrieved_Gtid_Set vs Executed_Gtid_Set |
差集 = 已收到但未执行的事务,即失败事务 |
Exec_Master_Log_Pos |
已执行到的位点 |
Seconds_Behind_Master基于事件时间戳估算,大事务回放期间可能显示为 0 但实际严重滞后 ,不能单独作为延迟判据,需结合pt-heartbeat或 GTID 差集。
三、按错误类型详解(现象 / 原理 / 处理)
3.1 数据一致性类(SQL 线程,最常见的"同步中断")
(1)1032 --- Can't find record / HA_ERR_KEY_NOT_FOUND
现象
Last_SQL_Errno: 1032
Last_Error: Could not execute Delete_rows/Update_rows event on table db.t;
Can't find record in 't', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND
原理
主库执行 DELETE/UPDATE,binlog(ROW 格式)记录了要删除/更新的行;从库回放时按主键/唯一键找不到该行。根因是主从数据已不一致,常见来源:
- 从库被直连写入(未开
super_read_only); - 逻辑备份恢复(mysqldump 非一致性点)导致基线不一致;
- 表无主键/唯一键,ROW 事件无法精确定位行;
- 曾用
slave_skip_errors无差别跳过,掩盖了历史错误; - 主库 purge binlog 后强行改位点。
处理
sql
-- ① 停止复制,确认失败事务
STOP SLAVE; -- 8.0: STOP REPLICA;
SHOW SLAVE STATUS\G -- 记录 Retrieved/Executed GTID 差集
-- ② 评估:数据能否丢弃
-- 能丢弃(如测试数据/可重建):按 GTID 注入空事务跳过
SET @@SESSION.GTID_NEXT='201aff26-1857-11eb-adaf-00505625b4dc:11';
BEGIN; COMMIT;
SET @@SESSION.GTID_NEXT='AUTOMATIC';
START SLAVE;
-- ③ 不能丢弃:先从主库补齐该行(按主键查主库、REPLACE 到从库),再跳过
-- ④ 不一致面大:用 pt-table-sync 修复,或直接重建从库
位点模式下(非 GTID):
sql
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
原则 :单次精确跳过优于 slave_skip_errors 全局跳过;后者"见错就跳",会持续放大不一致。
(2)1062 --- Duplicate entry ... for key
现象
Last_SQL_Errno: 1062
Last_Error: Could not execute Write_rows event on table db.t;
Duplicate entry '1' for key 'PRIMARY'
原理
从库已存在相同主键/唯一键记录,回放主库的 INSERT 时冲突。根因同样是主从数据不一致(从库被写入、双主同时写、备份基线含新数据、INSERT ... SELECT 在 STATEMENT 格式下重复执行等)。
处理(推荐顺序)
sql
-- ① 停复制,定位冲突行
STOP SLAVE;
SELECT * FROM db.t WHERE id = <冲突值>; -- 从库
-- 在主库核对同一行是否为"应保留版本"
-- ② 方案A:以主库为准覆盖从库
REPLACE INTO db.t VALUES (...); -- 或 DELETE 从库多余行
-- ③ 方案B:直接跳过该事务(GTID)
SET @@SESSION.GTID_NEXT='uuid:txn';
BEGIN; COMMIT;
SET @@SESSION.GTID_NEXT='AUTOMATIC';
START SLAVE;
-- ④ 工具化:pt-slave-repair 自动解析主库 binlog,
-- 将 UPDATE/INSERT 反转为 REPLACE INTO 写回从库后跳过
前置条件:binlog_format=ROW、binlog_row_image=FULL,否则工具解析不可靠。
双主/双向复制场景,冲突往往是双方同时写同一主键,需从业务层拆分写入或使用不同自增步长,而非长期靠跳过。
(3)1146 --- Table 'db.t' doesn't exist
原理
主库 binlog 里有对 db.t 的 DML,但从库该表不存在。常见于:
- 从库误执行
DROP TABLE/DATABASE; - 复制过滤规则(
replicate_do_table/replicate_wild_do_table)导致 DDL 被过滤而 DML 未过滤; - 主从表结构变更未同步执行。
处理
sql
SHOW SLAVE STATUS\G -- 确认缺失对象与事件位点
SHOW CREATE TABLE db.t; -- 主库取结构
-- 从库补建表(含索引),再继续
START SLAVE;
若确认为过滤规则造成,应修正 CHANGE REPLICATION FILTER 并注意其重启后不持久化的问题,需写入配置文件。
(4)1054 --- Unknown column
原理 :两端表结构不一致,主库 binlog 中引用的列在从库不存在。典型于"先改主库、后改从库"的滚动变更窗口,或 ALTER 在从库失败。
处理:暂停复制 → 在从库补齐列/对齐结构 → 继续。结构变更应使用工具保证两端顺序一致。
(5)1264 / 1366 / 1406 --- 数据超长、非法值、截断
原理 :主从 sql_mode 不一致(如主库宽松、从库严格),主库能写入的值在从库回放时被拒绝。
处理
sql
SELECT @@sql_mode; -- 主从分别执行,对齐
SHOW WARNINGS; -- 定位具体列/行
-- 统一两端 sql_mode 后重启复制
(6)1213 / 1205 --- 死锁 / 锁等待超时
原理 :从库回放时与从库本地查询/备份(如 xtrabackup 的 FTWRL、Kill query timeout)争锁。
1213:检测到死锁环,立即回滚代价最小事务;1205:等锁超过innodb_lock_wait_timeout。
处理
sql
SHOW ENGINE INNODB STATUS\G -- LATEST DETECTED DEADLOCK
SET GLOBAL innodb_print_all_deadlocks=ON; -- 记录全部死锁
-- 排查从库是否有长查询/备份占用;必要时错峰备份
应用侧重试即可恢复;反复出现需优化从库查询或备份窗口。
(7)从库被写入导致 SQL 线程停止
原理:复制要求从库只读,直写从库会造成与主库冲突(后续表现为 1032/1062)。
处理
sql
SET GLOBAL read_only=1;
SET GLOBAL super_read_only=1; -- 同时限制 SUPER 权限用户
super_read_only 是从库防误写的关键加固项。
3.2 连接与认证类(IO 线程)
(1)1045 --- Access denied for user 'repl'@'x.x.x.x'
现象
Last_IO_Errno: 1045
Last_IO_Error: error connecting to master 'repl@ip:3306' - retry-time: 60 retries: N
message: Access denied for user 'repl'@'ip' (using password: YES)
原理 :复制账号密码错误、账号不存在、host 不匹配、缺少 REPLICATION SLAVE 权限,或认证插件不兼容。
处理
sql
-- 从库验证账号可登录
mysql -h<master_ip> -urepl -p -P3306
-- 主库确认账号与权限
SELECT user,host,plugin FROM mysql.user WHERE user='repl';
SHOW GRANTS FOR 'repl'@'<slave_ip>';
-- 需具备:GRANT REPLICATION SLAVE ON *.* TO 'repl'@'<slave_ip>';
-- 修正后重建
STOP SLAVE; RESET SLAVE ALL;
CHANGE MASTER TO
MASTER_HOST='<master_ip>', MASTER_PORT=3306,
MASTER_USER='repl', MASTER_PASSWORD='***',
MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=1242,
GET_MASTER_PUBLIC_KEY=1;
START SLAVE;
(2)2061 / 2059 --- caching_sha2_password 认证插件失败
现象
Authentication plugin 'caching_sha2_password' reported error:
Authentication requires secure connection
原理 :MySQL 8.0 默认 caching_sha2_password,首次认证需要 TLS 或 RSA 公钥交换;复制命令未开启公钥获取即失败。
处理(三选一)
sql
-- 方案A:复制命令开启公钥获取(推荐)
CHANGE MASTER TO ... , GET_MASTER_PUBLIC_KEY=1;
-- 方案B:使用 TLS
CHANGE MASTER TO ... , MASTER_SSL=1;
-- 方案C:账号改为 mysql_native_password(注意 8.4 起默认不再启用该插件)
ALTER USER 'repl'@'<slave_ip>' IDENTIFIED WITH mysql_native_password BY '***';
(3)2003 / 2013 --- 连接不上 / 连接中断
| 错误 | 含义 | 常见原因 |
|---|---|---|
2003 Can't connect to MySQL server |
TCP 层连不上 | 主库未启动、端口错、bind-address 限制、防火墙、skip-networking |
2013 Lost connection during query |
连接建立后被断 | 网络抖动、wait_timeout、中间设备超时、大事务传输被打断 |
处理
bash
telnet <master_ip> 3306
# 或
nc -zv <master_ip> 3306
sql
SHOW VARIABLES LIKE 'bind_address';
SHOW VARIABLES LIKE 'skip_networking';
SHOW VARIABLES LIKE 'wait_timeout';
网络类问题需同时调大 MASTER_CONNECT_RETRY,并检查 Slave_IO_Running: Connecting 的持续时间。
(4)1236 --- Could not find first log file name in binary log index file
现象
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log:
'Could not find first log file name in binary log index file'
原理 :从库请求的 binlog 文件在主库已被 purge(expire_logs_days / binlog_expire_logs_seconds 到期、手工 PURGE BINARY LOGS、RESET MASTER),从库位点"悬空"。
同码还有另两种消息:
Client requested master to start replication from position > file size(位点超过文件大小);Slave has more GTIDs than the master has(从库 GTID 超前于主库,多见于主从切换/回切)。
处理
sql
-- 主库确认现存最早 binlog
SHOW BINARY LOGS;
SHOW MASTER STATUS;
-- 若所需 binlog 确已不存在,跳过无效:必须重建
-- 方式1:主库全备 + 记录位点,恢复到从库
mysqldump --single-transaction --master-data=2 --all-databases > full.sql
-- 方式2(推荐大库):xtrabackup 物理备份
xtrabackup --backup --target-dir=/backup/full
xtrabackup --prepare --target-dir=/backup/full
-- 恢复后按备份中的 binlog 位点/GTID 重建复制
预防 :主库 binlog 保留时长必须大于"最长从库故障恢复时间";建议 binlog_expire_logs_seconds 不低于 7 天。
(5)server_id / server_uuid 重复
现象
-
SHOW SLAVE STATUS报错或复制不推进; -
错误日志出现:
A replica with the same server_uuid/server_id as this replica has connected to the source
原理
server_id是复制拓扑内节点身份标识,重复会导致事件被当成"自己发出"而丢弃,或 dump 线程被踢;server_uuid在数据目录初始化时生成并存于auto.cnf,克隆数据目录搭建从库会导致 UUID 相同。
处理
sql
SHOW VARIABLES LIKE 'server_id';
SHOW VARIABLES LIKE 'server_uuid';
ini
# my.cnf 中为每个实例设置全局唯一 server_id
[mysqld]
server_id=2
UUID 冲突:停止实例 → 删除数据目录下 auto.cnf → 重启自动生成 → 重建复制。
3.3 Relay Log 类
(1)1594 --- Relay log read failure
现象
Last_SQL_Errno: 1594
Last_Error: Relay log read failure: Could not parse relay log event entry
原理:relay log 文件损坏或截断,SQL 线程无法解析事件。根因:
- 从库磁盘 IO 错误;
- 从库异常 crash / 断电导致 relay log 不一致;
- 磁盘空间写满,relay log 写入不完整(关注
Relay_Log_Space、max_relay_log_size); - 存储介质故障。
处理
sql
STOP SLAVE;
-- 记录当前已执行位点:Relay_Master_Log_File + Exec_Master_Log_Pos
SHOW SLAVE STATUS\G
-- 丢弃损坏的 relay log,从已执行位点重新拉取
RESET SLAVE; -- 8.0: RESET REPLICA;
CHANGE MASTER TO
MASTER_HOST='...', MASTER_USER='...', MASTER_PASSWORD='...',
MASTER_LOG_FILE='<Relay_Master_Log_File>',
MASTER_LOG_POS=<Exec_Master_Log_Pos>;
START SLAVE;
GTID 模式更简单:
sql
STOP SLAVE; RESET SLAVE;
CHANGE MASTER TO MASTER_HOST='...', MASTER_USER='...', MASTER_PASSWORD='...',
MASTER_AUTO_POSITION=1;
START SLAVE;
若磁盘/介质存在硬件错误,必须先处理硬件,否则重拉后仍会损坏;损坏严重且数据可疑时按"重建从库"处理。
(2)1593 及 relay log 相关写入失败
多为 relay log 文件无法打开/写入(权限、空间、inode 耗尽)。检查:
bash
df -h; df -i
ls -l <datadir>/relay-log*
处理:清理空间/修正属主权限后 RESET SLAVE 重拉。
3.4 GTID 与位点类
(1)GTID 不连续 / gap
原理 :从库本地手工执行了事务,或复制过滤规则丢弃了某些 GTID,导致 gtid_executed 与主库集合不连续,后续事务无法衔接。
处理
sql
STOP SLAVE;
SHOW GLOBAL VARIABLES LIKE 'gtid_executed';
SHOW GLOBAL VARIABLES LIKE 'gtid_purged';
-- 注入空事务补齐冲突 GTID
SET @@SESSION.GTID_NEXT='uuid:缺失编号';
BEGIN; COMMIT;
SET @@SESSION.GTID_NEXT='AUTOMATIC';
START SLAVE;
注意 :sql_slave_skip_counter 在 GTID 模式下不可用。
(2)GTID 模式下跳过事务的标准模板
sql
STOP SLAVE;
SET @@SESSION.GTID_NEXT='<uuid>:<txn_no>';
BEGIN;
COMMIT;
SET @@SESSION.GTID_NEXT='AUTOMATIC';
START SLAVE;
SHOW SLAVE STATUS\G -- 确认 Slave_SQL_Running=Yes、Executed_Gtid_Set 已包含该事务
3.5 配置类
(1)binlog_format 不一致
原理 :STATEMENT 格式记录 SQL 原文,含 NOW()、RAND()、UUID()、LIMIT 无 ORDER BY 等不确定语句时,从库重放结果可能不同,造成静默不一致;ROW 记录行变更,是复制一致性的基础。
处理
sql
SHOW VARIABLES LIKE 'binlog_format';
SET GLOBAL binlog_format='ROW'; -- 并写入 my.cnf 持久化
主从两端、级联链路各层必须一致。
(2)log_replica_updates(旧名 log_slave_updates)
原理:控制从库是否把回放的事务再写入自己的 binlog。
- 级联复制 A→B→C:B 必须为
ON,否则 C 收不到 B 上回放的数据; - 主从切换:新主若未开启,切换后其 binlog 缺失历史,下游断裂。
处理
sql
SHOW VARIABLES LIKE 'log_replica_updates';
SET GLOBAL log_replica_updates=ON;
(3)CHANGE REPLICATION FILTER 重启失效
原理 :过滤规则不持久化,实例重启后丢失;若同时未设置 skip_slave_start,复制线程自动拉起但过滤规则已无,导致本该忽略的库被同步,引发冲突。
处理 :将过滤规则同时写入 my.cnf,或使用持久化的复制通道配置文件。
3.6 性能类:复制延迟
现象 :Seconds_Behind_Master 持续增大,或 GTID 差集不断扩大。
原理与分流
sql
SHOW SLAVE STATUS\G
-- 观察 Relay_Log_Pos 是否变化
| 观察 | 判断 | 排查方向 |
|---|---|---|
Relay_Log_Pos 长时间不变 |
正在回放大事务 | 解析 binlog/relay log 定位表与操作类型;到主库慢日志按时间点找 SQL;拆分大事务 |
Relay_Log_Pos 持续变化但延迟不降 |
从库持续回放,吞吐不足 | 检查磁盘 IO、CPU;并行回放是否被卡住;从库是否有长查询/备份抢占资源 |
常用命令
sql
-- 从库当前活跃事务(确认大事务)
SELECT * FROM information_schema.INNODB_TRX\G
-- 并行复制配置
SHOW VARIABLES LIKE 'slave_parallel_workers'; -- 8.0: replica_parallel_workers
SHOW VARIABLES LIKE 'slave_parallel_type'; -- LOGICAL_CLOCK(8.0.27+ 默认)
SHOW VARIABLES LIKE 'binlog_transaction_dependency_tracking';
-- 精确延迟测量(避免 Seconds_Behind_Master 失真)
pt-heartbeat --update -h master -D test --interval=1
pt-heartbeat --monitor -h slave -D test
优化方向
- 提升并行度:
replica_parallel_workers、replica_parallel_type=LOGICAL_CLOCK; - 大事务拆小批提交;
- 从库
innodb_flush_log_at_trx_commit、sync_binlog按可靠性要求权衡; - 避免从库跑重查询/备份与回放争抢 IO;
- 检查网络带宽与中间设备限速。
3.7 半同步复制
现象:主库等待 ACK 超时后自动降级为异步,安全性下降。
原理 :rpl_semi_sync_master_timeout(默认 10000ms)内未收到从库 ACK,主库关闭半同步、退化为异步;恢复响应后回到增强半同步。
处理
sql
SHOW VARIABLES LIKE 'rpl_semi_sync%';
SHOW STATUS LIKE 'Rpl_semi_sync_master_status';
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; -- 未收到ACK的事务数
-- 从库确认插件启用
SET GLOBAL rpl_semi_sync_slave_enabled=ON;
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD; -- 重新注册半同步
排查点:从库 IO 线程是否正常、网络 RTT、从库负载是否导致 ACK 延迟。
四、故障处置决策树
复制中断
│
├─ Last_IO_Errno 有值? ──是──→ 连接/认证/主库binlog问题
│ 1045/2061 → 修账号、插件、公钥
│ 2003/2013 → 网络、防火墙、bind-address
│ 1236 → binlog被purge,只能重建
│
└─ Last_SQL_Errno 有值? ──是──→ 回放问题
│
├─ 1032/1062/1146/1054/1264 → 数据或结构不一致
│ │
│ ├─ 影响行少、可精确修复 → 补数据后跳过该事务
│ ├─ 影响面中等 → pt-table-sync 修复 + 校验
│ └─ 影响面大/无法评估 → 重建从库(最稳妥)
│
├─ 1594/1593 → relay log损坏 → RESET SLAVE 后从已执行位点重拉
├─ 1213/1205 → 锁冲突 → 错峰备份、优化从库查询
└─ GTID gap → 注入空事务补齐
三条底线原则
- 能补数据就不要跳过:跳过只是让复制"继续跑",不一致仍然存在。
- 单次精确跳过优于全局跳过 :
slave_skip_errors会掩盖后续所有同类错误,一致性彻底失守。 - 无法评估时重建 :
mysqldump --single-transaction --master-data=2或xtrabackup全备重建,是恢复一致性的最终手段。
五、重建从库标准流程(兜底方案)
bash
# 1) 主库全备(InnoDB,不锁表)
mysqldump --single-transaction --master-data=2 --routines --triggers \
--all-databases > /backup/full_$(date +%F).sql
# 记录备份中的 CHANGE MASTER TO ... MASTER_LOG_FILE/POS
# 或物理备份
xtrabackup --backup --target-dir=/backup/full
xtrabackup --prepare --target-dir=/backup/full
sql
-- 2) 从库恢复前停止复制并清空旧配置
STOP SLAVE;
RESET SLAVE ALL;
-- 3) 导入数据后重建复制(GTID 模式)
CHANGE MASTER TO
MASTER_HOST='<master_ip>', MASTER_PORT=3306,
MASTER_USER='repl', MASTER_PASSWORD='***',
MASTER_AUTO_POSITION=1,
GET_MASTER_PUBLIC_KEY=1;
START SLAVE;
-- 4) 验证
SHOW SLAVE STATUS\G
-- 要求:Slave_IO_Running=Yes、Slave_SQL_Running=Yes、
-- Seconds_Behind_Master=0、Retrieved/Executed GTID 一致
一致性校验
bash
# 逐表校验(主库执行,从库对比)
pt-table-checksum h=<master>,u=<user>,p=<pwd> --databases=<db> --no-check-binlog-format
# 发现差异后修复
pt-table-sync --print --sync-to-master h=<slave>,u=<user>,p=<pwd> --databases=<db>
也可用 CHECKSUM TABLE 对所有非系统表取校验值后比对。
六、预防措施(比修复更重要)
| 措施 | 作用 |
|---|---|
binlog_format=ROW + binlog_row_image=FULL |
保证回放确定性、工具可解析 |
| 每张表必须有主键 | ROW 事件可精确定位,避免 1032 |
从库 read_only=1 + super_read_only=1 |
杜绝直写从库造成的不一致 |
server_id 全局唯一、auto.cnf 不跨机拷贝 |
避免身份冲突 |
| binlog 保留时长 > 最长故障恢复窗口 | 避免 1236 |
定期 pt-table-checksum 校验 |
提前发现静默不一致 |
| 大事务拆分、控制单事务行数 | 降低延迟与回放风险 |
结构变更两端有序执行、统一 sql_mode |
避免 1054/1146/1264 |
监控 Slave_IO_Running/Slave_SQL_Running/Seconds_Behind_Master/GTID 差集 |
故障早发现 |