根本原因是主从数据状态不匹配:主库写入时可能用insert ignore等忽略冲突,而mysqlbinlog重放仅执行字面insert语句,当从库已存在同主键/唯一键记录时即报1062。

mysqlbinlog重放时触发1062,根本原因不是“重复”,而是数据状态不匹配
直接用mysqlbinlog重放主库 binlog 到从库(或测试库),报ERROR 1062 Duplicate entry,通常不是因为语句本身有问题,而是目标库已存在同主键/唯一键的记录——而你重放的是一条INSERT,不是INSERT IGNORE或REPLACE INTO。binlog 记录的是“执行结果”,不是“应用逻辑”。主库当时可能靠应用层去重、或用了ON DUPLICATE KEY UPDATE,但从库重放时只认语句字面意思。
常见场景包括:
- 你用
mysqlbinlog --base64-output=DECODE-ROWS -v解析出某条INSERT,手动复制到从库执行 - 用
mysqlbinlog | mysql批量重放一段日志,但目标库已有部分数据(比如之前同步过、或人为插入过) - 重放的是
STATEMENT格式日志,语句含NOW()、UUID()等非确定函数,导致主从插入不同值,但主键冲突仍发生
别用--skip-xxx参数硬跳,mysqlbinlog本身不支持跳过错误
mysqlbinlog命令行工具没有--skip-duplicate-key或类似开关。它只是把 binlog 解析成 SQL 文本流,后续执行失败与否,完全取决于接收端 MySQL 的行为。试图加--force或--stop-never也无效——这些参数控制的是解析过程,不是执行过程。
真正起作用的,是接收端 MySQL 的配置或会话级设置:
-
SET SESSION sql_log_bin = 0;:仅禁用当前会话的 binlog 写入,不影响执行逻辑,对1062无用 -
SET SESSION unique_checks = 0;:关闭唯一索引检查,但会破坏数据一致性,且INSERT仍可能因主键冲突失败(主键是聚簇索引,不是普通唯一键) -
SET SESSION foreign_key_checks = 0;:只影响外键,和1062无关 - 唯一有效的是在执行前临时改写 SQL,或换用带容错能力的工具
安全跳过1062的三种实操路径
核心原则:不掩盖错误,而是让重放逻辑适配目标库现状。
-
路径一:预处理SQL,把INSERT转成INSERT IGNORE
用
sed或awk批量替换(谨慎验证):mysqlbinlog mysql-bin.000001 | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u root -p
⚠️ 注意:INSERT IGNORE对主键和所有唯一键都生效,若业务依赖ON DUPLICATE KEY UPDATE的更新逻辑,此法会丢更新 -
路径二:用pt-table-sync做差异修复,而非盲重放
先定位哪几张表有冲突:
pt-table-sync --sync-to-master h=slave_host,D=db,t=table --print再生成修复语句:pt-table-sync --sync-to-master h=slave_host,D=db,t=table --execute✅ 它自动判断主从差异,只补漏、不重复插,比mysqlbinlog重放更精准 -
路径三:手动确认后,先删再插(适合单条或少量)
从
Last_SQL_Error或mysqlbinlog输出中提取冲突主键值,例如Duplicate entry '123' for key 'PRIMARY':DELETE FROM your_table WHERE id = 123;
再执行原INSERT语句 ✅ 最可控,但需确保删除操作不会误伤关联数据
最容易被忽略的点:重放前没关read_only,或没设sql_log_bin=0
如果你是在从库上用mysqlbinlog | mysql重放,且该从库启用了read_only=ON,命令会直接报错ERROR 1290,根本到不了1062那步。必须先执行:
SET GLOBAL read_only = OFF;然后才执行重放命令。但注意:重放完成后务必恢复:
SET GLOBAL read_only = ON;否则从库可能被误写入,埋下后续1062隐患。另外,若重放目的是调试而非真实同步,建议加上
SET SESSION sql_log_bin = 0;,避免重放操作又被记进本机 binlog,造成循环或污染。











