slave_sql_running: no且last_sql_error含access denied,根本原因是mysql库被replicate_ignore_db屏蔽,导致权限语句未同步;需检查并清除从库该配置,确保主库权限变更能写入binlog并被回放。

根本原因不是账号密码错了,而是权限变更压根没同步过去——mysql.user 表默认不走 binlog,从库查不到用户、连不上、报 Access denied for user,全是这个机制导致的。
为什么 SHOW SLAVE STATUS 显示 Slave_SQL_Running: No 且 Last_SQL_Error 含 Access denied
这说明 SQL 线程在回放一条权限相关语句(比如 GRANT 或 CREATE USER)时失败了。常见现象包括:
- 主库执行了
CREATE USER 'repl'@'%',但从库SELECT user, host FROM mysql.user返回空 - 从库应用连接时报
ERROR 1045 (28000)或ERROR 1141 (42000) -
SHOW SLAVE STATUS\G中Replicate_Ignore_DB字段值含mysql
本质是:MySQL 对 mysql 库的 DDL/DML 做了硬编码跳过处理,即使你开了 log_bin、配了 binlog_format=ROW,只要 replicate_ignore_db=mysql 生效,权限语句就进不了中继日志。
如何确认是不是被 replicate_ignore_db 屏蔽了 mysql 库
这是八成问题的根源,尤其当配置通过 Ansible 或容器模板批量下发时容易被忽略。
- 直接查状态:
SHOW SLAVE STATUS\G,看Replicate_Ignore_DB字段是否包含mysql - 查当前生效的过滤规则:
SELECT * FROM performance_schema.replication_applier_configuration; - 检查从库配置文件(
my.cnf),确认没有replicate_ignore_db = mysql或replicate_do_db = xxx这类显式限制 - GTID 模式下还要额外检查
binlog_ignore_db是否也屏蔽了mysql
为什么不能直接 INSERT INTO mysql.user 修复
手动改表看似快,但会触发一连串连锁故障:
-
INSERT INTO mysql.user不触发权限重载,FLUSH PRIVILEGES必须手动补,否则内存权限不生效 - 字段顺序、
authentication_string加密方式、密码过期策略等极易出错,从库可能静默拒绝该行 - 该操作不会生成合法 binlog 事件,SQL 线程回放时大概率报
ERROR 1786 (HY000)(GTID 不一致)或直接中断 - 5.7 及更早版本中,这类 DML 根本不记 binlog;8.0+ 即使记录,格式也常与原生 GRANT 不兼容
正确修复路径:让权限变更真正进 binlog 并被回放
核心原则是“主库发指令,从库自动执行”,而不是在从库本地硬改。
- 主库上用标准 DDL:
CREATE USER 'repl'@'%' IDENTIFIED BY 'xxx'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; - 确保主库
log_bin = ON且未配binlog_ignore_db = mysql - 从库确认
replicate_ignore_db不含mysql,必要时STOP SLAVE; RESET SLAVE;清除旧配置再重配 - 若已中断且急需恢复连接,可在从库临时执行一次
CREATE USER+GRANT(仅用于打通 IO 线程),但必须立刻在主库补上同操作,否则下次权限变更仍不同步 - GTID 模式下严禁
SET GLOBAL sql_slave_skip_counter = 1,应改用SET GTID_NEXT='xxx'; BEGIN; COMMIT;或重置gtid_purged
最容易被忽略的一点:很多团队只检查主库有没有开 log_bin,却忘了从库的 replicate_ignore_db 是独立配置项,可能继承了错误模板——权限不同步,卡在这一步的占绝大多数。











