在MySQL高可用集群环境中,权限数据分布在各节点的系统库mysql中,包含user、db、tables_priv、columns_priv等核心表。一旦主节点授权后在从节点未生效,应用便会出现账号不存在或拒绝访问的异常。理解权限数据在集群内的同步机制,是排查与预防不一致问题的基础。

一、MySQL权限数据的存储与复制原理
MySQL将所有用户账号、密码哈希、库表级权限保存在mysql系统库中。在传统主从复制里,除少数早期版本外,绝大多数DCL语句(如CREATE USER、GRANT、REVOKE)会以二进制日志事件形式发往从库并重放。在组复制(MGR)中,这些操作作为事务被组内共识协议排序后应用,理论上具备强一致潜力。
但要注意,部分版本对CREATE USER的处理存在特殊性:当关闭GTID时,某些DDL可能被记录为非事务事件,若中途出错易导致从库跳过该权限变更。因此生产环境务必开启gtid_mode=ON与enforce_gtid_consistency=ON,使权限类语句以事务方式复制,降低断点风险。
1.1 权限表与复制通道
权限表属于InnoDB引擎后,已能参与普通事务复制。可通过下方语句确认表引擎:
SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'mysql'
AND TABLE_NAME IN ('user','db','tables_priv','columns_priv');
若引擎均为InnoDB,说明权限数据可随事务提交进入binlog。在MGR中,所有节点都可读写,但建议仅由主节点统一执行DCL,避免多节点并发授权引发冲突回滚。
二、常见权限不一致场景与原因
实际运维中,权限不一致常表现为:主库新建账号成功,从库查询mysql.user无记录;或主库回收权限后,从库仍保留。原因多为节点直接修改mysql库、复制过滤规则屏蔽mysql库、或集群脑裂后旧主数据未合并。
另一个隐蔽问题是使用statement格式binlog时,包含函数调用的GRANT语句可能在从库重放结果不同。应设binlog_format=ROW,确保权限行级变更精确同步。同时检查是否有replicate_wild_ignore_table配置误伤mysql库。
2.1 直接改表导致的漂移
有些应急操作会直接UPDATE mysql.user后执行FLUSH PRIVILEGES,这种绕过binlog的改法不会同步到其他节点。正确做法永远是用GRANT或CREATE USER语句:
-- 错误示例(仅本地生效)
UPDATE mysql.user SET authentication_string=PASSWORD('tmp') WHERE User='app';
FLUSH PRIVILEGES;
-- 正确示例(写入binlog)
ALTER USER 'app'@'%' IDENTIFIED BY 'tmp';
前者在主从架构中会让从库账号密码停留旧值,应用故障切换后认证必然失败。后者由服务器层生成标准DCL事件,集群各节点均可重放。
三、保障权限一致性的实践方案
最稳妥的方案是结合GTID与组复制一致性读。对于异步主从,可部署监控脚本周期性比对主从权限快照;对于MGR,应配置group_replication_consistency=AFTER以保证读已提交。
此外,使用Percona的pt-show-grants工具可导出所有节点授权语句并diff。发现差异时,应在主节点重放缺失的GRANT,而非手动改从库。以下为简单比对思路:
# 在主节点导出 pt-show-grants -h 192.168.0.1 -u root -p > master_grants.sql # 在从节点导出 pt-show-grants -h 192.168.0.2 -u root -p > slave_grants.sql # 比对 diff master_grants.sql slave_grants.sql
3.1 集群参数建议
下表列出关键参数与推荐值:
| 参数 | 推荐值 | 作用 |
|---|---|---|
| gtid_mode | ON | 事务级复制标识 |
| enforce_gtid_consistency | ON | 禁止非GTID安全语句 |
| binlog_format | ROW | 行级同步防偏差 |
| group_replication_consistency | AFTER | MGR读一致保障 |
照此配置,权限变更会作为事务被集群共识,从库应用前主库已收到多数派确认,大幅降低不一致窗口。
四、故障排查与修复步骤
当发现权限不一致,先在主库执行SHOW GRANTS FOR 'user'@'host'确认期望状态,再到异常节点查mysql.user。若确为缺失,切勿直接INSERT,而应在主库重跑原GRANT,利用复制自然补齐。
若复制已中断,用GTID集对比找出漏洞,通过 Clone 或跳过特定事务修复。修复后观察Performance Schema中的 replication_applier_status 确保无报错。日常应将权限变更纳入发布流程,禁止人工登节点改库。
权限数据一致性不是单独功能,而是复制链路、参数规范与操作纪律的共同结果。把DCL当业务SQL一样走审批与审计,集群权限就不会“悄悄”分歧。