SHOW GRANTS FOR 'user'@'host' 是最准确的实时权限快照,能还原实际生效的授权语句(含角色继承),但需严格匹配用户和主机,不支持通配符批量查询。

直接查 mysql.user 表只能看到全局权限开关,看不到具体授权语句
MySQL 的 mysql.user 表只存了账号的全局级权限字段(如 Select_priv、Insert_priv),但这些是布尔值,无法还原出你当初执行的 GRANT 语句。比如你给 'app'@'192.168.%' 授了 SELECT 权限在 orders 库上,这个信息根本不在 user 表里——它存在 mysql.db、mysql.tables_priv 等更细粒度的系统表中。
所以不能只查 user 表,得拼多个系统表,或者用更可靠的方式:
- 优先用
SHOW GRANTS FOR 'user'@'host'—— 它能还原出实际生效的授权语句(包括从角色继承的) - 若用户不存在或权限被显式撤销过,
SHOW GRANTS仍会返回结果,但可能和当前生效权限不一致(需结合FLUSH PRIVILEGES状态判断) -
mysql.user表里的authentication_string字段现在默认存的是哈希值,不是明文密码,别误以为能从中反推权限
SHOW GRANTS 是最准的实时权限快照,但必须指定具体用户
它不支持通配符批量查所有用户,只能一个个来。常见做法是先查出所有用户,再循环执行 SHOW GRANTS:
SELECT CONCAT('SHOW GRANTS FOR ''', user, '''@''', host, ''';')
FROM mysql.user
WHERE user != '';
把结果复制进客户端执行,或用脚本自动处理。注意两点:
-
host字段可能含通配符(如%或10.%.%.%),SHOW GRANTS必须严格匹配,'admin'@'%'和'admin'@'localhost'是两个不同账号 - 如果用户有角色(MySQL 8.0+),
SHOW GRANTS默认只显示直接授予的权限;加FOR ROLE才能看到角色本身的权限定义 - 输出里带
WITH GRANT OPTION的行要特别留意——说明该用户还能给别人授同样权限,安全风险更高
想导出所有用户的完整授权语句?用 mysqldump 备份权限表最稳妥
直接 dump mysql 库的权限相关表,比手写 SQL 拼接更少出错:
mysqldump --no-create-info --skip-extended-insert mysql user db tables_priv columns_priv procs_priv proxies_priv
这样导出的是 INSERT 语句,可读性差但绝对完整。关键点:
-
--skip-extended-insert让每条记录单独成行,方便 grep 查某个用户 -
db表存数据库级权限(如SELECTontest.*),tables_priv存表级,columns_priv存列级——粒度越细,对应表越容易被忽略 - MySQL 8.0 后新增
role_edges和default_roles表,涉及角色继承关系,dump 时也建议加上
权限视图不一致?检查 sql_mode 和 MySQL 版本差异
MySQL 5.7 和 8.0 的权限模型差别不小,比如:
- 8.0 默认启用
sql_mode=STRICT_TRANS_TABLES,某些旧版授权语句(如没写IDENTIFIED BY)在 8.0 可能报错或行为不同 -
CREATE USER在 5.7 是语法糖,在 8.0 是强制前置步骤;没显式创建就直接GRANT,5.7 会隐式建用户,8.0 会报错 - 用
information_schema.role_table_grants查角色权限时,5.7 根本没有这个视图
跨版本迁移权限前,务必确认目标实例的 sql_mode 和是否启用了 activate_all_roles_on_login,否则 SHOW GRANTS 输出可能漏掉角色继承的部分。
权限不是静态快照,它依赖当前生效的配置、角色激活状态和缓存刷新情况。哪怕刚执行完 GRANT,没 FLUSH PRIVILEGES(或等效操作),新权限也可能不立即生效——这点最容易被忽略。


















