grant在主库执行后从库仍报access denied,是因为replicate_ignore_db=mysql导致权限变更未同步;需检查从库show slave status\g中replicate_ignore_db是否含mysql,并避免直写mysql.user表,改用grant或mysqldump同步权限。

为什么GRANT在主库执行了,从库还是Access denied
因为MySQL默认不把mysql.user表的变更写入binlog——哪怕你执行了CREATE USER或GRANT,语句根本没进binlog,从库自然收不到。5.7默认不记录,8.0+虽默认记录,但前提是:log_bin=ON且没配replicate_ignore_db=mysql。
- 检查从库
SHOW SLAVE STATUS\G里的Replicate_Ignore_DB字段是否含mysql - 主库执行
GRANT后,用SHOW BINLOG EVENTS LIMIT 10确认是否有对应事件(如Write_rows_v1) - 别信“配置一样就同步”,容器模板或Ansible批量下发时,
replicate_ignore_db常被无意识继承
用mysqldump手动同步权限表的实操要点
这是中小规模集群(≤20节点)最可控的方式,但参数错一个就可能覆盖运维账号或导入失败。
- 导出时必须加
--where="Host!='localhost'",否则root@localhost被覆盖,从库彻底失联 - 必须加
--no-create-info:8.0和5.7的mysql.user字段差异大(如account_locked、plugin),建表语句会冲突 - 导入前所有从库先
STOP SLAVE,避免同步中写入导致主键冲突 - 导入命令示例:
mysql -h slave_host -u root -p mysql ,不能用<code>source——它不支持USE mysql切换
Ansible自动化同步时必须拦截的三类错误
脚本跑通≠权限生效。Ansible容易静默跳过关键失败,比如用户已存在、密码策略不匹配、角色未启用。
-
CREATE USER失败时,MySQL 8.0+默认静默忽略(IF NOT EXISTS没加),结果是GRANT报错ERROR 1133 (HY000):用户不存在 -
GRANT带WITH GRANT OPTION时,若目标用户没SELECT权限查mysql.user,语句直接失败,但mysql_query模块默认不报错 - 角色绑定后必须逐台执行
SET DEFAULT ROLE,否则用户登录后权限为空——这个操作不写binlog,Ansible里得单独任务
GTID模式下权限同步最容易踩的坑
GTID不是万能解药,反而会放大版本不一致带来的问题。
- 主库用
CREATE ROLE,从库是5.7?直接报ERROR 3528 (HY000)中断复制,跳过事务解决不了根本 - 主库
ALTER USER ... PASSWORD EXPIRE,从库版本低于8.0.19?password_expired字段不存在,回放失败 - 用
pt-table-sync对比mysql.user?它无法处理authentication_string字段的跨版本哈希差异(如caching_sha2_passwordvsmysql_native_password)
权限同步不是“执行一次就完事”。每次通过phpMyAdmin、Navicat或运维脚本改权限,都得触发同步流程——没人盯住,三天内必然出现节点间SHOW GRANTS结果不一致。











