必须成对配置auto_increment_increment和auto_increment_offset并写入my.cnf的[mysqld]段且重启生效,A设increment=2/offset=1生成奇数ID,B设increment=2/offset=2生成偶数ID,否则必现主键冲突。

双主复制不是配完 server-id 和 log-bin 就能跑通的——自增 ID 冲突是上线即崩的高频雷,必须靠 auto_increment_increment 和 auto_increment_offset 配对生效,缺一不可。
为什么只改 auto_increment_offset 会失效
只设 auto_increment_offset = 2,但没动 auto_increment_increment(仍为默认 1),结果就是:A 节点插出 1、2、3,B 节点也插出 1、2、3。offset 只管“第一个值”,increment 才决定“下一个值跳多远”。两者必须配合,否则等于没配。
- 两节点时,
auto_increment_increment必须设为 2;三节点则必须为 3,以此类推 -
auto_increment_offset每台机器只能取 1 到 increment 之间的整数,且不能重复(如三节点分别设 1/2/3) - 临时 SET GLOBAL 修改后,MySQL 重启就丢,生产环境必须写进
my.cnf的[mysqld]段并重启服务
配置必须写进 my.cnf 并重启,不能只靠 SET GLOBAL
运维常犯的错:在 MySQL 客户端里执行 SET GLOBAL auto_increment_increment = 2,以为生效了。其实这只是会话级临时覆盖,mysqld 进程一重启,参数立刻回滚到配置文件值(或默认值)。双主切主时若参数丢失,新主库继续用默认步长 +1,马上和另一台撞 ID。
- 正确做法:编辑
/etc/my.cnf或/etc/mysql/my.cnf,在[mysqld]下添加两行:auto_increment_increment = 2auto_increment_offset = 1(A 节点)auto_increment_increment = 2auto_increment_offset = 2(B 节点) - 确认配置段落正确:不能写到
[client]或[mysql]下,否则完全不加载 - MySQL 8.0+ 可用
SET PERSIST持久化,但依然建议优先走配置文件,避免版本兼容风险
验证是否真生效:别信配置文件,要看运行时值
改完配置、重启 mysqld 后,必须连上每台实例执行 SQL 验证,不能只看配置文件有没有写对。
- 执行:
SELECT @@auto_increment_increment, @@auto_increment_offset;—— 两台返回值必须严格符合规划(如 A 是 2/1,B 是 2/2) - 建测试表:
CREATE TABLE test_inc (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; - A 上插入 3 行:
INSERT INTO test_inc VALUES (),(),();→ 查SELECT id FROM test_inc;应得1,3,5 - B 上同样操作应得
2,4,6;如果出现1,2,3,说明 offset 没生效,大概率是配置写错段落或没重启
双主写入前必须关掉 sql_log_bin,否则维护脚本会污染 binlog
日常运维中,你可能需要手动补数据或修复脏数据。此时如果 sql_log_bin = ON,这些语句会被记入 binlog,并同步到另一台主库,极大概率触发主键冲突、复制中断。
- 安全做法:连上目标实例后,先执行
SET SESSION sql_log_bin = OFF;(仅当前会话关闭) - 再执行 INSERT/UPDATE 等维护语句
- 完成后记得
SET SESSION sql_log_bin = ON;(虽然会话结束自动恢复,但显式恢复更稳妥) - 绝对不要依赖
INSERT IGNORE或ON DUPLICATE KEY UPDATE来“兜底”——它们只对单条语句有效,无法解决并发插入时的竞态
最容易被忽略的一点:已存在表的 AUTO_INCREMENT 值不会因改参而重算。比如某表当前 AUTO_INCREMENT = 100,你把 offset 改成 2、increment 改成 3,下一条插入仍是从 100 开始,然后跳到 103、106……所以改参前务必用 SHOW CREATE TABLE 检查当前值是否留有足够空间,避免跳过中间值后很快触顶溢出。


















