mysql 8.0 双向主从必须手动配置两套主从链路,关键包括:server-id 全局唯一(如1/2)、auto-increment-increment=2且offset错开(1/2)、binlog_format=row、gtid_mode=on、log_slave_updates=on、replicate-same-server-id=0。

MySQL 8.0 无法“一键开启”双向主从互备,必须手动配两套独立的主从链路,并严格隔离自增 ID、禁用循环复制、强制 GTID —— 漏掉任一配置,写入就会失败或数据错乱。
server-id 和 auto-increment 必须成对错开
这是最常被跳过的硬性前提。两个节点的 server-id 必须不同(如 A=1、B=2),且不能是默认值 1(尤其在容器或自动化部署中容易重复);auto-increment-increment 必须统一设为相同值(推荐 2),auto-increment-offset 则必须错开(A=1、B=2)。
- 若未设 offset,两台机器 INSERT 不带 ID 时都会生成
1,立刻报Duplicate entry '1' for key 'PRIMARY' - 已有存量数据时,需人工确认 A 的最大 ID 是奇数、B 是偶数,否则启动复制即中断
- Windows 上配置文件是
my.ini,Linux/macOS 是/etc/my.cnf或/etc/mysql/my.cnf,路径别写错
binlog_format=ROW + gtid_mode=ON 是强制组合
binlog_format 必须显式设为 ROW,不能依赖默认值(MySQL 8.0 默认仍是 STATEMENT);同时必须启用 GTID:设 gtid_mode = ON 和 enforce_gtid_consistency = ON。这两项不配齐,双主下时间函数、UUID、用户变量等会导致两边数据不一致。
- 验证方式:
SELECT @@binlog_format;返回ROW,SELECT @@gtid_mode;返回ON - 改完配置必须重启
mysqld,仅SET GLOBAL不生效 - 如果之前用过传统复制(file/pos 模式),务必先执行
STOP SLAVE; RESET SLAVE ALL;清空旧状态
log_slave_updates=ON 和 replicate-same-server-id=0 缺一不可
双向链路成立的前提是:A 收到 B 的变更后,要能再转发给其他节点(包括 B 自己)。所以 log_slave_updates = ON 让从库也写 binlog;而 replicate-same-server-id = 0 则防止 A 把自己刚写进 binlog 的事件又读回来重放,造成无限循环。
- 这两个参数必须在两台机器的配置文件中都显式写出,不能只靠“默认关闭”
- 某些 Docker 镜像或云数据库托管服务会覆盖默认值,
SHOW VARIABLES LIKE 'replicate_same_server_id';必须返回OFF(即 0) -
log_slave_updates开启后,磁盘 IO 和 binlog 体积会上升,建议配合expire_logs_days = 7控制日志生命周期
CHANGE MASTER TO 必须用 MASTER_AUTO_POSITION=1
GTID 模式下,CHANGE MASTER TO 绝对不能混用 MASTER_LOG_FILE 和 MASTER_LOG_POS,必须指定 MASTER_AUTO_POSITION = 1。否则复制线程启动失败,或者同步位置错乱。
- 建复制用户时,host 推荐用
'repl'@'%',避免因 IP 变动或 DNS 解析失败中断连接 - 密码含
!、$等 shell 特殊字符时,不要在命令行里拼CHANGE MASTER TO,直接进 MySQL CLI 粘贴执行 - 验证是否真同步:看
SHOW SLAVE STATUS\G中Seconds_Behind_Master是否稳定为 0,且Retrieved_Gtid_Set与Executed_Gtid_Set完全相等
真正难的不是敲完这些命令,而是后续——应用层必须规避无条件 UPDATE、敏感业务(如支付)不能双写、同一张表的并发更新必须加时间戳或版本号校验。配置只是骨架,业务逻辑才是血肉,漏掉这点,同步再稳也救不了数据一致性。











