主从切换后AUTO_INCREMENT值不一致会导致主键冲突,必须在切换前统一配置、校验并手动修正各节点的自增值,且GTID模式下仍需单独检查。

主从切换后 AUTO_INCREMENT 值不一致,直接导致写入冲突
MySQL 主从切换后,如果原主库和新主库的 auto_increment_offset 和 auto_increment_increment 配置没对齐,或者从库在提升为主库前没手动修正 AUTO_INCREMENT 值,新主库可能分配出已存在于旧主库(现从库)中的 ID,造成主键冲突。典型现象是应用报错:Duplicate entry '12345' for key 'PRIMARY'。
- 必须在切换前确认所有节点的
show variables like 'auto_increment%';一致;若使用双主或环形复制,auto_increment_increment应设为大于等于节点数的值(如 2 节点设为 2),auto_increment_offset各节点错开(如 1 和 2) - 切换后立刻在新主库上执行
SELECT MAX(id) FROM table_name;,再用ALTER TABLE table_name AUTO_INCREMENT = N;手动设为该最大值 +1 —— 注意这个 N 必须大于当前所有从库中该表的最大 ID - 不要依赖
SHOW SLAVE STATUS的Exec_Master_Log_Pos来判断“数据已追平”,它不反映自增 ID 分配状态;真正要查的是各节点上对应表的MAX(id)
mysqld 启动时 auto_increment_offset 不生效?检查配置加载顺序
MySQL 启动时若同时在命令行、my.cnf、my.ini 或运行时 SET 中设置了 auto_increment_offset,优先级会覆盖预期值。最常见情况是:配置文件写了 auto_increment_offset = 2,但启动脚本里又加了 --auto-increment-offset=1,结果以命令行为准。
- 用
mysql -e "SHOW VARIABLES LIKE 'auto_increment%';"查运行时实际值,不是看配置文件 -
auto_increment_offset和auto_increment_increment必须成对设置,且offset必须在 1 到increment之间(含),否则 MySQL 启动时会静默重置为 1 - 动态 SET(如
SET @@auto_increment_offset = 3;)只对当前会话有效,不持久化,切勿用于主从一致性保障
GTID 模式下 AUTO_INCREMENT 冲突更隐蔽,但修复逻辑不变
开启 GTID 后,主从切换通常走 CHANGE MASTER TO MASTER_AUTO_POSITION = 1,看起来更可靠,但 AUTO_INCREMENT 仍完全独立于 GTID 管理——GTID 只保证事务不重复执行,不保证自增值不重复生成。
- 即使
gtid_executed完全一致,也不能说明各节点的AUTO_INCREMENT值同步;必须单独校验 - 使用
mysqldump --set-gtid-purged=OFF备份时,如果源库AUTO_INCREMENT值偏高,恢复到新实例后会继承该值,但若未校准,可能和线上其他节点冲突 - Percona Toolkit 的
pt-table-checksum不检查自增列值,它只比对行内容;要查 ID 分布,得自己写脚本遍历关键表的MAX(id)
从库提升为主库后,INSERT ... SELECT 可能跳过自增校验
当从库被提升为主库,且应用开始往它写入数据时,如果用了 INSERT INTO t1 SELECT id+1000, ... FROM t2 这类语句,MySQL 不会校验生成的 id+1000 是否已存在,也不会触发 AUTO_INCREMENT 机制——它只是普通值插入。一旦这个计算值撞上已有主键,就直接报错。
- 这种写法绕过了自增保护,本质上是业务逻辑缺陷,不能靠数据库参数修复
- 上线前应扫描代码中所有
INSERT ... SELECT、REPLACE、INSERT ... ON DUPLICATE KEY UPDATE,确认是否显式指定了主键值 - 临时补救:在新主库上给关键表加
UNIQUE索引(如果还没加),让冲突提前暴露;长期方案是改用INSERT ... SELECT不带主键列,交由AUTO_INCREMENT分配










