MHA故障切换后mysql.user权限不自动同步,因ROW模式下GRANT不生成binlog且replicate_ignore_db=mysql默认跳过系统库,须人工导出权限SQL、SET sql_log_bin=0后在新主执行并验证。

MySQL高可用切换后,mysql.user等权限表不会自动同步,新主库的权限状态停留在切换前快照——这不是配置遗漏,而是 MySQL 默认行为。必须人工介入补全,否则应用连接失败、从库复制中断都是大概率事件。
为什么 GRANT 语句在切换后失效
权限变更(如 GRANT、CREATE USER)在 binlog 中是否被记录,取决于三件事:是否启用 binlog_format = STATEMENT、是否禁用了 replicate_ignore_db=mysql、以及是否在主库执行。但现实中,绝大多数生产环境用的是 binlog_format = ROW,而 ROW 模式下 GRANT 本身不生成 binlog 事件;即使设为 STATEMENT,只要配置了 replicate_ignore_db=mysql(默认开启),所有对 mysql 库的写操作都会被跳过。
- 检查从库是否启用该过滤:
SHOW VARIABLES LIKE 'replicate_ignore_db';,若返回mysql,说明权限变更根本不会进入 relay log -
FLUSH PRIVILEGES不写 binlog,且在从库执行无意义,只会掩盖问题 - 直接
UPDATE mysql.user或INSERT INTO mysql.db是危险操作:绕过权限校验逻辑,不同版本字段结构可能不兼容(如password_expired在 5.7+ 中由服务端维护),极易导致主从数据分裂
如何导出和重放权限 SQL
必须使用 mysqldump 导出可读、可复用的权限语句,而非 mysqldump 全库或直接拷贝表文件。关键在于排除数据、禁用扩展插入,并限定只导出权限相关表。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 导出命令(在旧主或任意健康主库上执行):
mysqldump --no-data --skip-extended-insert --databases mysql --tables user db tables_priv procs_priv proxies_priv - 导出结果中会包含
CREATE USER和GRANT语句,但注意:MySQL 8.0 的角色(ROLE)和动态权限(如BACKUP_ADMIN)需确认从库版本是否支持,否则会报错ERROR 3528 - 在新主上执行前,先关闭 binlog 记录:
SET sql_log_bin = 0;,再 source SQL 文件;完成后立即SET sql_log_bin = 1; - 执行完别忘了验证:
SELECT User, Host FROM mysql.user;和SHOW GRANTS FOR 'app'@'%';
MHA 切换后权限同步的实操节奏
MHA 自身不处理权限同步,它只负责选主、补 relay log、重置从库指向。权限补全必须作为切换流程的强制步骤嵌入脚本,不能“之后再补”——因为旧主恢复为从库时,如果权限缺失,IO 线程会因找不到用户而卡在 Got fatal error 1236。
- 切换前:定期(如每天凌晨)在主库运行导出命令,把权限 SQL 推送到共享存储或 Git 仓库,确保有最新快照
- 切换中:MHA
master_ip_failover脚本里,在start阶段(即新主已提升、VIP 已漂移后)立刻调用mysql -u root -e "SET sql_log_bin=0; SOURCE /path/to/privs.sql;" - 切换后:检查新主的
mysql.user行数是否与旧主导出时一致;同时登录旧主(此时应为从库),执行SHOW SLAVE STATUS\G,确认Seconds_Behind_Master = 0且无SQL_Delay干扰
最易被忽略的一点:GTID 模式下,CREATE USER 若因密码策略失败回滚,从库可能已部分应用——这意味着权限 SQL 必须在所有节点版本一致的前提下执行,且不能依赖“自动重试”。手动导出 + 显式关闭 sql_log_bin + 立即验证,是目前唯一可靠路径。










