高可用切换后新主库应用账号权限缺失,根本原因是mysql系统库未同步,权限字段全为n或空;须在切换脚本中用pt-show-grants导出原主库权限快照,并在新主库执行mysql -u root -p mysql grants.sql重放。

高可用切换后新主库应用账号权限缺失,不是应用连不上,而是账号存在但权限全空——mysql.user 表里该账号的 Select_priv、Insert_priv 等字段全为 N 或 ''。根本原因是:多数高可用方案(如 MHA、Orchestrator、ProxySQL 故障转移)只同步数据目录或复制 relay log,不主动同步 mysql 系统库,更不会触发 FLUSH PRIVILEGES。
为什么 failover 后权限会丢?
MySQL 权限信息全部存于 mysql 库的 user、db、tables_priv 等表中,而这些表默认不参与主从复制(replicate_ignore_db = mysql 是常见配置)。即使你开了 binlog_format = ROW,mysql 库也因特殊标记被跳过写入 binlog。所以当新主库是通过提升备库(而非克隆)上位时,它的 mysql 库仍是旧备库初始化时的状态,和原主库完全无关。
- 查证方式:
SELECT User, Host, Select_priv, Insert_priv FROM mysql.user WHERE User = 'app_user';—— 如果全是N,就是权限没同步 - 别信
SHOW GRANTS FOR 'app_user'@'%',它可能缓存旧结果;必须查mysql.user表字段值 - 注意 host 匹配:主库上是
'app_user'@'10.0.1.%',但新主库上可能只有'app_user'@'localhost',这是常见漏点
如何在 failover 后快速恢复权限?
不能等下次人工迁移再补,得在切换脚本里加一步——用原主库的权限快照生成可执行 SQL,在新主库上重放。最稳的是用 pt-show-grants,不是手写 GRANT 语句。
- 切换前,在原主库运行:
pt-show-grants --user=root --password=xxx --host=old-master > grants.sql - 确保
grants.sql包含CREATE USER(默认开启),否则新主库上用户不存在 - failover 完成、新主库已可写后,立刻执行:
mysql -u root -p mysql (注意必须指定 <code>mysql数据库) - 不用手动
FLUSH PRIVILEGES——GRANT和CREATE USER语句本身就会刷新内存权限缓存 - 如果原主库已不可达,且无
grants.sql备份,只能登录原主库(若还能读)跑:SELECT CONCAT('GRANT ', GROUP_CONCAT(priv SEPARATOR ', '), ' ON ', db, '.* TO ''', User, '''@''', Host, ''';') FROM mysql.db GROUP BY User, Host, db;,再手工补全其他权限表逻辑
为什么不能直接 mysqldump mysql 库做 failover 前置备份?
可以 dump,但不能直接导入新主库——因为高可用切换通常发生在主库宕机后,你没机会提前 dump;就算提前 dump 了,5.7 的 mysql 库结构在不同小版本间也有细微差异(比如 password_last_changed 字段是否允许 NULL),硬灌可能失败或导致后续 ALTER USER 报错。
-
mysqldump -u root -p --skip-lock-tables --routines --triggers --events mysql > mysql_pre_failover.sql只适用于“计划内切换”场景 - 导入前必须确认目标实例已初始化:
ls /var/lib/mysql/mysql/user.ibd存在,否则mysql -u root -p mysql会报 “Unknown database 'mysql'” - 导入命令必须带数据库名:
mysql -u root -p mysql ,写成 <code>mysql -u root -p 会进 <code>test库,权限语句全失效 - 跨小版本(如 5.7.28 → 5.7.34)dump/restore 一般没问题;但遇到
ERROR 1067 (42000),就说明字段默认值不兼容,得退回到pt-show-grants方案
最容易被忽略的 host 和 plugin 兼容性问题
权限恢复后仍连不上?大概率是 Host 字段不匹配,或认证插件变了。5.7 默认是 mysql_native_password,但某些部署会改用 sha256_password,而新主库初始化时可能用了不同插件。
- 查新主库用户插件:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'app_user'; - 如果
plugin是sha256_password但客户端不支持,临时切回:ALTER USER 'app_user'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd'; -
Host必须精确匹配:应用连的是10.0.1.5,但权限只给了'app_user'@'10.0.1.%'—— 这没问题;但如果给了'app_user'@'10.0.1.0/24'(CIDR 格式),MySQL 5.7 不识别,会当成字面量 host,导致匹配失败 - 特别注意
localhost:Unix socket 连接走'app_user'@'localhost',TCP 连接走'app_user'@'%'或具体 IP;两者权限记录必须分开存在
权限不是“有或没有”的开关,而是由 User+Host+plugin+表字段值共同决定的元数据状态。failover 后的权限缺失,本质是系统库未同步导致的元数据漂移——修复它,靠的不是重启或刷新,而是让新主库的 mysql 表内容真正对齐原主库快照。











