最稳妥的mysql权限迁移方式是用pt-show-grants导出标准grant语句,需人工编辑剔除测试账号、调整host网段、补全require ssl,并清理目标库同名用户后执行flush privileges。

用 pt-show-grants 导出可读、可审计的 GRANT 语句
这是最稳妥的迁移起点。它不碰系统表,不依赖版本兼容性,输出的就是你能一眼看懂的 GRANT 和 CREATE USER 语句。
在源库(开发/旧服务器)执行:
pt-show-grants --user=root --password=xxx --host=127.0.0.1 > grants.sql
导出后必须人工编辑,否则直接导入会出问题:
- 删掉所有测试账号、
'root'、'mysql.session'、'mysql.sys' - 把
'dev_user'@'localhost'改成生产用的'app_user'@'10.20.30.%'—— 注意 host 要匹配真实连接来源 - 检查是否含
REQUIRE SSL;若缺失且生产要求强制加密,手动补上 - 确认密码插件一致:若目标库是 MySQL 5.7,而源库用户用了
caching_sha2_password,需在导入后执行ALTER USER 'app_user'@'10.20.30.%' IDENTIFIED WITH mysql_native_password BY 'xxx';
导入前必须清空目标库同名用户
直接导入会导致权限叠加,不是覆盖,而是累加。比如原已有 'app_user'@'10.20.30.%',再导入一次 GRANT SELECT ON db1.*,结果就是多了一条权限,而不是重置。
登录目标库,先清理:
SELECT CONCAT('DROP USER ''', user, '''@''', host, ''';') FROM mysql.user WHERE user NOT IN ('root', 'mysql.session', 'mysql.sys');
复制输出结果执行,或批量运行。之后务必执行:
FLUSH PRIVILEGES;
注意:DROP USER 会同时删除该用户所有权限,比 REVOKE 更彻底;不要跳过这步,否则后续导入的权限可能被“遮蔽”。
避免 host 匹配失效的三个关键点
权限不生效,90% 是因为 host 字段没对上。MySQL 的匹配逻辑是“最长前缀优先”,不是模糊匹配。
- 应用实际连上来的是什么 IP?查:
SELECT host FROM information_schema.processlist WHERE user = 'app_user';—— 别只信配置文件里的网段 - 如果走代理或容器网络,
host可能是内网 VIP 或 Pod IP,不是你预设的10.20.30.%,得提前采集真实值再写 - 新服务器若没开
skip_name_resolve,MySQL 会做反向 DNS 查询;如果 DNS 不通或解析慢,'app_user'@'db.example.com'就可能匹配失败,建议统一用 IP 段
跨版本迁移时认证插件必须显式处理
MySQL 8.0 默认用 caching_sha2_password,但很多旧客户端(PHP 7.2、某些 JDBC 驱动)不支持,连都连不上。
不能靠改全局配置一劳永逸:
- 导出前先查源库插件:
SELECT user, host, plugin FROM mysql.user WHERE user = 'app_user'; - 导入后,对每个需要兼容的用户单独降级:
ALTER USER 'app_user'@'10.20.30.%' IDENTIFIED WITH mysql_native_password BY 'xxx'; - 别用
--default-authentication-plugin=mysql_native_password初始化 mysqld —— 这会影响所有新建用户,包括未来管理员账号
真正容易被忽略的是:权限语句本身不包含认证方式,CREATE USER 语句里的 IDENTIFIED WITH 必须和 authentication_string 哈希值严格对应,否则导入后用户无法登录。











