mysql主从复制默认不同步mysql.user表权限,因旧版本不将grant等操作写入binlog;需确保binlog开启、不忽略mysql库、使用grant而非insert,并注意gtid一致性。

mysql.user 表不会自动同步到从库
MySQL 主从复制默认只同步 binlog 记录的 DML 和部分 DDL,而用户权限存在 mysql.user 表里,该表属于系统库,其变更(如 CREATE USER、GRANT)在旧版本(5.7 及之前)默认不写入 binlog,导致从库权限始终为空或过期。
常见错误现象:SELECT user,host FROM mysql.user 在主库查到用户,从库查不到;应用连从库报 Access denied for user;用 SHOW GRANTS FOR 'u'@'h' 在从库返回空或报错。
- MySQL 5.7 默认
skip-log-bin对系统表生效,GRANT语句不记 binlog —— 必须显式开启log_bin_trust_function_creators=1并确保binlog_format=ROW或MIXED - MySQL 8.0+ 改为默认将权限操作记为 DDL 事件写入 binlog,但前提是主库没关
log_bin,且没设置replicate_ignore_db=mysql(这是最常踩的坑) - 检查从库是否跳过了 mysql 库:运行
SELECT * FROM performance_schema.replication_applier_configuration或看SHOW SLAVE STATUS\G中的Replicate_Ignore_DB字段
用 GRANT 同步权限比 INSERT mysql.user 更可靠
直接 INSERT INTO mysql.user 或 UPDATE mysql.user 不触发权限重载,也不保证 binlog 正确记录;而 GRANT / CREATE USER 是原子性 DDL,在支持的版本中能正确生成 binlog 事件并被从库回放。
使用场景:新增运维账号、切换应用连接用户、临时开放只读账号给 BI 工具。
-
GRANT SELECT ON db.* TO 'reporter'@'%' IDENTIFIED BY 'pwd'; FLUSH PRIVILEGES;——FLUSH PRIVILEGES在主库非必须(GRANT自动重载),但从库如果延迟大,可手动执行一次确保内存权限即时生效 - 避免用
INSERT手动写mysql.user,字段顺序、加密方式(authentication_stringvspassword)、密码过期策略等极易出错 - MySQL 8.0+ 的角色(
CREATE ROLE)也走 binlog,但要求主从都为 8.0+,否则从库会因无法识别语法而中断复制
从库权限不一致时,别直接 mysqldump mysql 库
有人想“全量同步权限”,就 mysqldump --databases mysql 导出再导入从库 —— 这会导致从库 mysql 表和主库结构/数据强耦合,后续任何权限变更都可能因自增 ID、时间戳、内部字段(如 password_last_changed)冲突而让复制中断或权限异常。
性能与兼容性影响:dump 出的 mysql SQL 包含 CREATE DATABASE、DROP TABLE,可能覆盖从库已有配置(如插件、时区设置);且 mysql 表有外键和触发器依赖,跨版本 dump 极易失败。
- 真正安全的做法是:在主库执行完整权限操作(
CREATE USER+GRANT),确认SHOW BINLOG EVENTS里对应事件已写入,再等从库追平 - 紧急修复可用
SET SQL_LOG_BIN=0; INSERT ... ; FLUSH PRIVILEGES;在从库补,但仅限单次、明确知道主库不会重复执行同操作的场景 - 检查权限是否真同步:不要只查
mysql.user,还要看mysql.db、mysql.tables_priv—— 它们同样需通过GRANT触发,而非直改表
GTID 模式下权限同步更容易断
启用 gtid_mode=ON 后,所有事务带全局唯一标识,看似更可靠,但权限操作若在主库被隐式拆成多个事务(例如某些客户端工具执行 CREATE USER 后立刻 GRANT,中间夹了其他语句),从库可能因 GTID 冲突或空事务过滤而跳过部分权限写入。
容易被忽略的地方:GTID 复制要求主从 enforce_gtid_consistency=ON,而该参数会禁止不安全的语句(比如子查询里调用 UUID()),但也会让某些老脚本里的权限初始化逻辑静默失败。
- 验证 GTID 是否包含权限操作:
SELECT * FROM mysql.gtid_executed WHERE source_uuid = 'xxx' AND interval_start = N,结合SHOW BINLOG EVENTS IN 'xxx' FROM Y LIMIT 10定位具体事件 - 如果发现权限没同步,优先检查主库是否用了
--init-command或代理层(如 ProxySQL)拦截/改写了GRANT语句,这类中间件常把权限语句转成非事务形式 - GTID 模式下不要用
CHANGE MASTER TO ... MASTER_AUTO_POSITION=0切换为 file:pos 复制——这会让后续权限变更彻底脱离 GTID 轨迹,再也无法对齐
事情说清了就结束。权限同步不是“开了复制就自动好”的事,它卡在 binlog 配置、系统库过滤、语句类型、GTID 一致性四个实际可触达的点上。漏掉任何一个,都会让从库变成一个“看不见用户”的黑盒。











