双主复制必须在my.cnf的[mysqld]段配对设置auto_increment_increment=2和auto_increment_offset=1/2并重启生效,否则两节点均默认生成1,2,3…,同步时必然触发duplicate entry错误导致sql线程停止。

双主复制不配 auto_increment_offset 和 auto_increment_increment,基本等于没配——插入就报 ERROR 1062 (23000): Duplicate entry 'X' for key 'PRIMARY',复制线程直接停住。
为什么必须在 my.cnf 里写死这两个参数
MySQL 启动时,复制线程(IO/SQL)会一次性读取 auto_increment_increment 和 auto_increment_offset 的值并固化使用。仅执行 SET GLOBAL 或 SET PERSIST 只能临时生效,重启后还原为默认值(increment=1, offset=1),此时两个节点又开始抢着生成 ID 1、2、3……
常见错误现象:刚配置完测试正常,过两天服务重启,突然大量 Duplicate entry 报错,SHOW SLAVE STATUS\G 显示 SQL Thread 已停止。
- 必须把配置写进
my.cnf的[mysqld]段,不能写在[client]或其他段落 - 修改后必须
systemctl restart mysqld(或对应平台的重启方式),不能只 reload - 验证是否加载成功:连上 MySQL 执行
SELECT @@auto_increment_increment, @@auto_increment_offset;,结果必须与配置一致
两节点怎么配才不撞 ID
目标是让节点 A 专产奇数(1, 3, 5…),节点 B 专产偶数(2, 4, 6…)。这不是靠“运气”或“应用层控制”,而是靠底层参数强制错开。
- 两个节点都设
auto_increment_increment = 2 - 节点 A 设
auto_increment_offset = 1 - 节点 B 设
auto_increment_offset = 2 - 如果未来要扩到三节点(A/B/C),则统一设
increment = 3,再分别设offset = 1、2、3
注意:offset 值必须在 1 到 increment 之间(含端点),超出范围会被 MySQL 自动截断为 1,导致实际又撞车。
配置写对了但 ID 还是连续?检查这三点
你改了配置、也重启了,但 INSERT INTO test(id) VALUES() 在节点 A 上却生成了 1、2、3……说明参数根本没生效。
- 确认执行的是
SELECT @@auto_increment_increment,不是SHOW VARIABLES LIKE 'auto_increment%'—— 后者可能显示旧值(尤其未重启时) - 检查
my.cnf是否被!include覆盖:某些发行版(如 RHEL/CentOS)默认启用!includedir /etc/my.cnf.d/,你的配置可能被同名文件覆盖 - 确认表引擎是
InnoDB:MyISAM 对offset的行为不一致,且已淘汰;新建表务必显式指定ENGINE=InnoDB
快速验证法:建一张空表 CREATE TABLE inc_test (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;,在节点 A 插 3 行,查 SELECT id FROM inc_test; —— 应得 1,3,5;节点 B 同样操作应得 2,4,6。
GTID 模式下还要额外注意什么
如果启用了 GTID(强烈推荐),光调自增参数还不够:
- 必须开启
log_slave_updates = ON,否则从库产生的 binlog 不会被自身复制线程读取,GTID 链路断裂 - 必须设
gtid_mode = ON和enforce_gtid_consistency = ON,否则双主间无法建立 GTID 复制 - 不要依赖
slave-skip-errors来绕过主键冲突:它会让 SQL 线程跳过错误继续跑,但数据已不一致,后续更难修复
真正麻烦的从来不是配置本身,而是当复制中断几小时后,两边各自写了几百条记录,再恢复同步时——自增 ID 序列早已脱钩,这时参数再对也没用,只能人工比对、停写、补数据。











