MySQL主从复制默认不同步mysql.user表权限,因旧版本不将GRANT等操作写入binlog;需确保binlog开启、不忽略mysql库、使用GRANT而非INSERT,并注意GTID一致性。
mysql
.user 表不会自动同步到从库
MySQL 主从复制默认只同步
记录的 DML 和部分 DDL,而用户权限存在
表里,该表属于系统库,其变更(如
、
)在旧版本(5.7 及之前)默认不写入
,导致从库权限始终为空或过期。
常见错误现象:
在主库查到用户,从库查不到;应用连从库报
;用
在从库返回空或报错。
MySQL 5.7 默认
对系统表生效,
语句不记 binlog —— 必须显式开启
并确保
或
MySQL 8.0+ 改为默认将权限操作记为 DDL 事件写入 binlog,但前提是主库没关
,且没设置
(这是最常踩的坑)
检查从库是否跳过了 mysql 库:运行
或看
中的
字段
用 GRANT 同步权限比 INSERT mysql.user 更可靠
直接
或
不触发权限重载,也不保证 binlog 正确记录;而
/
是原子性 DDL,在支持的版本中能正确生成 binlog 事件并被从库回放。
使用场景:新增运维账号、切换应用连接用户、临时开放只读账号给 BI 工具。
——
在主库非必须(
自动重载),但从库如果延迟大,可手动执行一次确保内存权限即时生效
避免用
手动写
,字段顺序、加密方式(
vs
)、密码过期策略等极易出错
MySQL 8.0+ 的角色(
)也走 binlog,但要求主从都为 8.0+,否则从库会因无法识别语法而中断复制
从库权限不一致时,别直接 mysqldump mysql 库
有人想“全量同步权限”,就
导出再导入从库 —— 这会导致从库
表和主库结构/数据强耦合,后续任何权限变更都可能因自增 ID、时间戳、内部字段(如
)冲突而让复制中断或权限异常。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
性能与兼容性影响:dump 出的
SQL 包含
、
,可能覆盖从库已有配置(如插件、时区设置);且
表有外键和触发器依赖,跨版本 dump 极易失败。
真正安全的做法是:在主库执行完整权限操作(
+
),确认
里对应事件已写入,再等从库追平
紧急修复可用
在从库补,但仅限单次、明确知道主库不会重复执行同操作的场景
检查权限是否真同步:不要只查
,还要看
、
—— 它们同样需通过
触发,而非直改表
GTID 模式下权限同步更容易断
启用
后,所有事务带全局唯一标识,看似更可靠,但权限操作若在主库被隐式拆成多个事务(例如某些客户端工具执行
后立刻
,中间夹了其他语句),从库可能因 GTID 冲突或空事务过滤而跳过部分权限写入。
容易被忽略的地方:GTID 复制要求主从
,而该参数会禁止不安全的语句(比如子查询里调用
),但也会让某些老脚本里的权限初始化逻辑静默失败。
验证 GTID 是否包含权限操作:
,结合
定位具体事件
如果发现权限没同步,优先检查主库是否用了
或代理层(如 ProxySQL)拦截/改写了
语句,这类中间件常把权限语句转成非事务形式
GTID 模式下不要用
切换为 file:pos 复制——这会让后续权限变更彻底脱离 GTID 轨迹,再也无法对齐
事情说清了就结束。权限同步不是“开了复制就自动好”的事,它卡在 binlog 配置、系统库过滤、语句类型、GTID 一致性四个实际可触达的点上。漏掉任何一个,都会让从库变成一个“看不见用户”的黑盒。
binlogmysql.userCREATE USERGRANTbinlogSELECT user,host FROM mysql.userAccess denied for userSHOW GRANTS FOR 'u'@'h'skip-log-binGRANTlog_bin_trust_function_creators=1binlog_format=ROWMIXEDlog_binreplicate_ignore_db=mysqlSELECT * FROM performance_schema.replication_applier_configurationSHOW SLAVE STATUS\GReplicate_Ignore_DBINSERT INTO mysql.userUPDATE mysql.userGRANTCREATE USERGRANT SELECT ON db.* TO 'reporter'@'%' IDENTIFIED BY 'pwd'; FLUSH PRIVILEGES;FLUSH PRIVILEGESGRANTINSERTmysql.userauthentication_stringpasswordCREATE ROLEmysqldump --databases mysqlmysqlpassword_last_changedmysqlCREATE DATABASEDROP TABLEmysqlCREATE USERGRANTSHOW BINLOG EVENTSSET SQL_LOG_BIN=0; INSERT ... ; FLUSH PRIVILEGES;mysql.usermysql.dbmysql.tables_privGRANTgtid_mode=ONCREATE USERGRANTenforce_gtid_consistency=ONUUID()SELECT * FROM mysql.gtid_executed WHERE source_uuid = 'xxx' AND interval_start <= N AND interval_end >= NSHOW BINLOG EVENTS IN 'xxx' FROM Y LIMIT 10--init-commandGRANTCHANGE MASTER TO ... MASTER_AUTO_POSITION=0