MySQL集群中用户权限变更不会自动同步,因mysql系统库被MGR硬编码排除复制;须在所有节点幂等地执行CREATE USER IF NOT EXISTS和完整GRANT语句,并逐节点验证SHOW GRANTS、plugin一致性及真实连接。

在 MySQL 集群(MGR 或主从)中,用户账号与权限变更不会自动同步——这不是配置问题,而是硬编码限制。必须在所有节点上显式、幂等地执行 CREATE USER 和 GRANT 语句,并逐节点验证一致性。
为什么 GRANT 在 MGR 集群里执行后其他节点没反应
MySQL Group Replication 明确排除 mysql 系统库的复制,包括 mysql.user、mysql.db 等表的所有 DML/DDL 操作。哪怕你在主节点执行 GRANT SELECT ON mydb.* TO 'app'@'10.20.%',这条语句根本不会生成 binlog 事件,也不会通过组通信广播到其他节点。你看到“Query OK”,只是当前节点本地写入成功;其他节点查 SELECT User, Host FROM mysql.user 依然为空或旧状态,直连时必然报 Access denied。
常见误操作包括:
- 在从节点手动执行
GRANT(破坏集群一致性,后续主节点同名用户变更会冲突) - 用
INSERT INTO mysql.user直接改表(跳过服务端校验逻辑,在 8.0+ 中如account_locked字段由服务端维护,写入无效甚至引发崩溃) - 依赖
FLUSH PRIVILEGES(它不写 binlog,在 MGR 中纯属冗余,还可能掩盖权限未同步的问题)
怎样写出真正可跨节点执行的幂等授权语句
关键不是“怎么写对”,而是“怎么写得能在所有节点反复跑都不出错”。必须把权限变更拆解为可重放、无副作用的 SQL 序列:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 以
CREATE USER IF NOT EXISTS开头,避免某节点已存在用户导致脚本中断;例如:CREATE USER IF NOT EXISTS 'app'@'10.20.%' IDENTIFIED WITH caching_sha2_password BY 'xxx'; -
GRANT必须带完整ON子句和明确的@'host',禁止省略主机部分(否则默认为@'%',不同节点 DNS 解析差异会导致权限实际不一致) - MySQL 8.0+ 若启用密码策略,建议拆成两步:先
CREATE USER显式指定IDENTIFIED WITH caching_sha2_password,再GRANT;防止因节点间认证插件不一致(如有的用mysql_native_password)导致认证失败 - 涉及角色(
ROLE)时,需额外执行:CREATE ROLE IF NOT EXISTS→GRANT ... TO ROLE→GRANT role_name TO 'user'@'host'→SET DEFAULT ROLE(注意:最后一步SET DEFAULT ROLE必须在每台节点单独执行)
用 Ansible 自动化时必须验证的三件事
Ansible 是目前最可控的落地方式,但光靠 mysql_query 模块执行 SQL 远远不够。以下三项验证必须嵌入脚本末尾,缺一不可:
- 比对所有节点的
SHOW GRANTS FOR 'app'@'10.20.%'输出是否完全一致(注意空格、换行、大小写)——仅靠“SQL 执行成功”不等于权限同步完成 - 检查各节点
SELECT user, host, plugin FROM mysql.user WHERE user = 'app'的plugin字段是否统一(尤其混用 5.7 和 8.0 节点时) - 在每个节点用该账号尝试真实连接并执行一条简单查询(如
SELECT 1),确认认证与权限均生效
复杂点不在语法,而在“谁触发、何时触发、如何验证”。一次权限变更,本质是一次多节点协同操作;漏掉任一节点或任一验证项,都可能埋下 Access denied 或越权访问的隐患。










