MySQL双主双向复制默认不同步mysql系统库(如user、db表),因权限操作被MySQL硬编码跳过binlog,即使配置binlog-do-db=mysql也无效;必须通过人工导出INSERT语句并在另一节点手动导入实现权限对齐。

MySQL 双向复制(主主)本身不自动同步 mysql 系统库,包括 mysql.user、mysql.db 等权限表。默认配置下,即使你开了 log_slave_updates=1 和 binlog-do-db=mysql,大多数 MySQL 版本(尤其是 5.7+)仍会忽略对系统库的 binlog 记录,这是硬编码行为,无法绕过。
为什么 binlog-do-db=mysql 在双向复制中无效
MySQL 内部对 mysql 库的 DML 操作(如 CREATE USER、GRANT)做了特殊处理:即使显式配置了 binlog-do-db=mysql,这些语句也不会写入 binlog。这是出于安全与一致性考虑——避免从库因权限变更引发不可控的复制中断或权限错乱。
-
GRANT和CREATE USER本质是 DDL + 隐式 DML,MySQL 将其归类为“系统元数据操作”,跳过 binlog -
FLUSH PRIVILEGES不产生任何 binlog 事件,纯内存加载 - 即使手动执行
INSERT INTO mysql.user(不推荐),也会被拒绝或静默失败
如何让两端权限真正一致(实操路径)
必须放弃“靠复制自动同步权限”的想法,改用人工对齐 + 定期校验。核心原则:只在一个节点(比如 A)做权限变更,再通过脚本/工具同步到 B。
- 在 A 上执行权限变更后,立即导出权限语句:
mysqldump --no-create-info --skip-extended-insert -u root -p mysql user db procs_priv tables_priv columns_priv | grep -E "^(INSERT|REPLACE) INTO `?user`?|^(INSERT|REPLACE) INTO `?db`?" > grants.sql - 清理
grants.sql中的非权限行(如注释、空行),保留纯INSERT/REPLACE语句 - 将
grants.sql手动导入 B:mysql -u root -p mysql - 执行
FLUSH PRIVILEGES;在 B 上生效(注意:该命令不复制,必须两边都手动运行) - 验证是否一致:
SELECT host,user,authentication_string FROM mysql.user ORDER BY host,user;分别在 A/B 上执行并比对输出
使用 GTID 时权限同步更麻烦?
启用 gtid_mode=ON 后,问题没变少,反而多一个限制:不能在从库(即另一端的 master 角色)上直接修改 mysql 库,否则会触发 ERROR 1786 (HY000): Statement violates GTID consistency。
- GTID 要求所有事务可重放,而系统表更新不可预测,MySQL 主动禁止
- 这意味着你甚至不能在 B 上手动
INSERT INTO mysql.user来“补漏” - 唯一合规方式仍是:A 导出 → 清洗 → B 导入 →
FLUSH PRIVILEGES - 如果必须自动化,可用
pt-show-grants(Percona Toolkit)生成可移植的GRANT语句,而非直接操作系统表
最易被忽略的一点:权限同步不是“一次配置就完事”。只要任意一端执行了 CREATE USER 或 GRANT,另一端就必须立刻人工同步,否则下次 failover 或读写切换时,连接会直接被拒。没有捷径,也没有隐式机制。


















