直接比对两个环境用户权限差异,须先确认'user'@'host'元组完全一致,再用mysqlpump --users导出标准化权限,同步检查mysql.proxies_priv和role_edges表,并统一清理sql格式后diff,最后通过current_user()和真实连接验证生效权限。

直接比对两个环境的用户权限差异,不能只跑 SHOW GRANTS 然后 diff —— 因为 MySQL 的权限是按 'user'@'host' 组合生效的,SHOW GRANTS FOR 'alice' 可能匹配错行、漏掉实际账号,且不包含 PROXY 权限和角色继承关系。
先确认两个环境里“同一个用户”是否真对应同一账号
MySQL 不认用户名,只认 User + Host 元组。比如 'app_dev'@'192.168.10.%' 和 'app_dev'@'%' 是两个独立账号,权限可能完全不同。
- 在源环境执行:
SELECT User, Host FROM mysql.user WHERE User = 'app_dev'; - 在目标环境执行同样语句,逐条比对结果是否完全一致(注意大小写、IP 段通配符、空格)
- 若 Host 不一致,后续所有权限比对都失去意义——得先统一账号定义
- 别忽略系统用户:
mysql.session、mysql.sys这类账号不应出现在应用权限比对中,导出前必须过滤
用 mysqlpump --users 导出可比对的标准化权限语句
mysqldump --all-databases 不导出用户权限,SHOW GRANTS 手动拼又容易丢 WITH GRANT OPTION 或角色绑定;mysqlpump --exclude-databases=% --users 是 MySQL 8.0+ 最可靠的选择,它自动处理 caching_sha2_password 哈希格式、生成带 IF NOT EXISTS 的 CREATE USER,并完整包含 GRANT 和 SET DEFAULT ROLE。
- 导出命令示例:
mysqlpump --exclude-databases=% --users --skip-definer -u root -p > env1_users.sql - 务必加
--skip-definer,避免因 DEFINER 用户不存在导致导入失败 - 导出后用
grep -v '^$' | grep -v '^--' | sed 's/;$//' | sort -u清理空行、注释、分号,再保存为标准比对文件 - 注意:该命令需 root 或具备
SYSTEM_USER权限的账号执行,普通账号无权读取mysql.user表
比对时必须额外检查 mysql.proxies_priv 和角色继承
SHOW GRANTS 和 mysqlpump --users 都不输出 PROXY 权限(即 A 用户可代理登录 B 用户的能力),也不体现角色被授予给哪些用户——这两项差异在跨环境同步时极易被忽略,却直接影响登录行为和权限边界。
- 查 PROXY 权限:
SELECT * FROM mysql.proxies_priv WHERE User IN ('app_dev', 'app_prod') AND Host IN ('%', 'localhost'); - 查角色分配:
SELECT FROM_HOST, FROM_USER, TO_HOST, TO_USER FROM mysql.role_edges WHERE TO_USER IN ('app_dev', 'app_prod'); - 角色本身是否启用?执行
SELECT default_role FROM mysql.user WHERE User IN ('app_dev', 'app_prod');,值为''表示未设默认角色,即使授了角色也不会自动生效 - 这些表的查询结果也要标准化后加入比对范围,否则
diff会漏掉关键权限路径
diff 前必须统一上下文,否则全是“假差异”
权限语句里一个空格、换行位置、引号风格(' vs `)、是否含 REQUIRE NONE,都会让 diff 报出大量无关差异。更麻烦的是,不同 MySQL 版本生成的权限语句默认格式不同(如 8.0.33 加了 AS 'xxx',而 8.0.23 没有)。
- 不要直接 diff 原始 SQL 文件,先用
sed统一清理:sed -E "s/REQUIRE [^ ]+//g; s/ AS '[^']*'//g; s/ WITH GRANT OPTION//g; s/ ON \*\.\*//g" - 禁用
information_schema权限的用户执行SHOW DATABASES会报错,但这个错误不会体现在SHOW GRANTS输出里——所以权限差异 ≠ 实际访问能力差异,得结合CURRENT_USER()和真实连接测试验证 - 最易被跳过的验证步骤:在两个环境中用同一客户端 IP 连接,执行
SELECT CURRENT_USER(), USER();和SHOW GRANTS;,看返回是否一致——这才是最终生效的权限快照











