查权限需先确认用户存在且上下文正确,因mysql按'user'@'host'组合存储权限,不同host的同名用户权限独立;show grants不显示proxy权限,需查mysql.proxies_priv;导出建议用mysqldump或批量生成grant语句并标准化格式;权限比对须考虑生效优先级、隐式拒绝及连接上下文。

查权限别只看 SHOW GRANTS,得先确认用户存在且上下文正确
MySQL 的权限是按 'user'@'host' 组合存储的,同一个用户名在不同 host(比如 'alice'@'localhost' 和 'alice'@'%')是完全独立的账号。直接跑 SHOW GRANTS FOR 'alice' 可能报错或返回意外结果——因为没指定 host,MySQL 会按默认规则匹配,容易漏掉实际生效的权限行。
实操建议:
- 先用
SELECT User, Host FROM mysql.user WHERE User = 'alice';确认完整账号名 - 再对每个组合执行
SHOW GRANTS FOR 'alice'@'localhost';,逐条导出 - 注意:5.7+ 版本中,
SHOW GRANTS不显示PROXY权限,需额外查mysql.proxies_priv
导出权限时用 mysqldump 比手写 SQL 更可靠
人工拼 GRANT 语句容易丢参数、错大小写、漏 WITH GRANT OPTION,尤其遇到角色(ROLE)或动态权限(如 BACKUP_ADMIN)时更易出错。
实操建议:
- 用
mysqldump --no-create-info --no-data --compact --skip-extended-insert mysql user db tables_procs_priv proxies_priv导出权限表原始数据 - 若只要可读的
GRANT语句,用mysql -Nse "SELECT CONCAT('SHOW GRANTS FOR ''',User,'''@''',Host,''';') FROM mysql.user WHERE User IN ('alice','bob') AND Host IN ('localhost','%');" | mysql -N | sort批量生成并排序 - 导出后务必用
grep -v '^$' | sort -u去空行和重复,避免比对干扰
diff 比对前必须标准化格式,否则白忙活
权限语句里空格数量、换行位置、引号风格(单引双引)、是否带分号、是否含注释,都会让 diff 报大量“假差异”。比如 GRANT SELECT ON `db`.* TO 'u'@'h'; 和 GRANT SELECT ON `db`.* TO 'u'@'h'(少分号)会被当成两条不同语句。
实操建议:
- 统一加
;:用sed 's/$/;/'补全 - 统一引号:用
sed "s/'\([^']*\)'@'\([^']*\)'/`\1`@`\2`/g"把用户名 host 改成反引号包裹(兼容标识符含特殊字符) - 忽略空格差异:用
diff -w;忽略大小写:加-i;但别用-y(并排模式),它对长语句易折行错位
权限差异不等于“谁多谁少”,要看生效优先级和隐式拒绝
MySQL 权限检查是自顶向下:先查 user 表(全局),再 db,再 tables_priv…… 一条 DENY(8.0.16+ 的 REQUIRE 或 ROLE 拒绝逻辑)可能覆盖前面所有 GRANT。单纯比对 GRANT 语句列表,会漏掉这种“表面有权限、实际被拦住”的情况。
实操建议:
- 用
SELECT * FROM mysql.role_edges WHERE TO_HOST = 'alice'@'localhost';查角色继承链 - 检查
mysql.global_grants(8.0+)是否有SYSTEM_USER类动态权限影响行为 - 真要验证差异效果,不如直接用两个账号连上去跑
SELECT CURRENT_USER(), USER();+SHOW DATABASES;+SELECT COUNT(*) FROM information_schema.TABLE_PRIVILEGES;对照看
权限比对不是字符串 diff 游戏,核心是搞清“当前连接下,这条语句到底能不能执行”。中间环节任何一步没对齐 host、role、SSL 要求或 proxy 设置,结果就不可信。











