replace into 实际执行 delete + insert,导致主库 auto_increment 加 1,而从库 row 格式回放仅更新不增序,造成主从自增值不一致,切换后易触发主键冲突错误。

不是“丢失”,而是主从对自增计数器的更新逻辑不一致,尤其在特定语句和配置下会固化差异。
REPLACE INTO 或 INSERT ... ON DUPLICATE KEY UPDATE 触发主从 AUTO_INCREMENT 不同步
这是 MySQL 5.7 及更早版本中最隐蔽也最常踩的坑。主库执行 REPLACE INTO 遇到唯一键冲突时,内部实际做了 DELETE + INSERT,导致 AUTO_INCREMENT 计数器加 1;但从库的 binlog 是以 ROW 格式回放的,且只记录最终的 UPDATE 行为(不是 DELETE+INSERT),所以从库的计数器不增加。
- 现象:主库
SHOW CREATE TABLE t显示AUTO_INCREMENT=100,从库显示AUTO_INCREMENT=99 - 后果:一旦主从切换,新主库用旧值插入,大概率撞上已存在的 ID,报
ERROR 1062 (23000): Duplicate entry 'X' for key 'PRIMARY' - 修复不能靠重启或重连:该差异已写入表元数据,必须手动校准
innodb_autoinc_lock_mode = 2(交错模式)且主从配置不一致
MySQL 8.0 默认启用 innodb_autoinc_lock_mode = 2,它提升并发但放弃自增值顺序保证。如果主库设为 2、从库仍为 1 或 0,或主从 binlog_format 不统一(比如 MIXED vs ROW),就会导致从库回放时分配的自增值与主库不一致。
- 影响范围:主要是
INSERT ... SELECT、LOAD DATA这类批量插入 - 验证方式:在主库执行
INSERT INTO t SELECT * FROM t LIMIT 100,再查主从AUTO_INCREMENT值是否相同 - 底线要求:主从必须保持
innodb_autoinc_lock_mode和binlog_format完全一致,否则无法保证复制一致性
MySQL 重启后 InnoDB 表的 AUTO_INCREMENT 值“回退”
这不是复制问题,但常被误认为是主从不同步。InnoDB 在低版本(5.7 及之前)中仅将当前最大自增值缓存在内存,不持久化。MySQL 重启后,它会执行 SELECT MAX(id) FROM tbl 重新初始化计数器 —— 如果此时从库刚被切为主库,而原主库还在运行并写入了更高 ID,这个“回退”就会立刻引发冲突。
- 典型场景:主库宕机 → 从库升主 → 运维重启新主库 → 自增值被重算为旧最大值 → 新插入就撞
- MyISAM 没这问题:它的自增值存文件里,重启不丢;但生产环境几乎不用 MyISAM
- MySQL 8.0+ 已修复:InnoDB 现在会将计数器写入 redo log,重启后可恢复
真正麻烦的从来不是单点故障,而是多个机制叠加:比如用了 REPLACE INTO + innodb_autoinc_lock_mode=2 + 未校准重启后的计数器 —— 这时候光看错误日志根本分不清是哪一层出的问题。











