主备切换时自增ID冲突本质是新主库AUTO_INCREMENT值未对齐、配置未统一或从库曾被误写;必须配对设置auto_increment_increment与offset,双节点设increment=2、offset分别为1和2,三节点设increment=3、offset为1/2/3,且均需写入my.cnf重启生效,并在切换前用ALTER TABLE AUTO_INCREMENT=N校准(N为所有节点全局MAX(id)+1),同时封死从库误写路径。

主备切换时自增ID冲突报错,本质不是切换操作本身出问题,而是新主库的 AUTO_INCREMENT 值没对齐、配置没统一、或从库曾被误写——只要漏掉其中一环,就会立刻触发 Duplicate entry 'X' for key 'PRIMARY'。
必须配对设置 auto_increment_increment 和 offset
单设 auto_increment_offset 没用,它只决定第一个值;真正控制生成序列的是 increment 步长。两者必须绑定生效:
- 双节点:所有节点设
auto_increment_increment = 2,主库offset = 1(生成 1,3,5…),备库offset = 2(生成 2,4,6…) - 三节点或多主场景:设
increment = 3,各节点offset分别为 1、2、3,且必须在 1 到 increment 范围内,否则 MySQL 启动时会静默重置为 1 - 配置必须写入
my.cnf并重启生效;SET GLOBAL只影响新连接,复制线程仍用旧值
切换前必须手动校准新主库的 AUTO_INCREMENT 值
MySQL 启动时用 SELECT MAX(id) + 1 初始化自增值(5.7 及之前),不读 binlog,也不同步对方状态。不能依赖 SHOW SLAVE STATUS 显示“已追平”就认为 ID 安全。
- 在目标备库(即将升主)上执行:
SELECT MAX(id) FROM tbl_name; - 取所有节点中该表的 全局最大 id,再加 1,得到 N
- 执行:
ALTER TABLE tbl_name AUTO_INCREMENT = N;(N 必须严格大于当前所有节点该表的最大 id) - 用
SHOW CREATE TABLE tbl_name;确认元数据已更新
封死从库误写路径,杜绝源头风险
很多团队配对了参数、也做了校准,仍踩坑,往往因为从库在切换前已被应用直连写入过——哪怕只插了一条,就可能让自增计数器跑偏。
- 切换前确认备库处于
read_only = ON状态,且无活跃写入连接 - 检查
show global status like 'Com_insert';在切换窗口前后是否增长 - 如有跨库写入历史,需逐台查
SELECT MAX(id),取最大值再 +1,不能只看本机
GTID 模式下也不能放松警惕
开启 GTID 只保证事务不重复执行,不管理自增值生成逻辑。即使 gtid_executed 完全一致,各节点的 AUTO_INCREMENT 值仍完全独立。
- GTID 不替代 offset/increment 配置,也不自动校准自增计数器
- 切换后仍要执行上述校准步骤,不可省略
- 用
mysqldump --set-gtid-purged=OFF恢复时,若源库自增值偏高,目标实例会继承该值,但若未核对全局最大 id,仍可能与其他节点冲突

















