SHOW GRANTS FOR 'user'@'host' 是唯一可靠方式,因其自动合并全局、库级、表级等所有权限层级并展开已激活角色,避免手动查多表导致的漏项或误判。

直接执行 SHOW GRANTS FOR 'user'@'host' 是唯一可靠方式
MySQL 的权限不是扁平存储的,而是分层叠加:全局(mysql.user)、库级(mysql.db)、表级(mysql.tables_priv)、列级、角色继承、动态权限……手动查多张表极易漏项或误判。只有 SHOW GRANTS FOR 会自动合并所有来源,输出真实生效的授权语句。
常见错误现象:SELECT * FROM mysql.user WHERE User = 'xxx' 只返回 Select_priv: Y,但用户实际无法查任何表——因为该用户没被授库级权限,而 mysql.user 里的 Y 仅表示“有全局 SELECT 权限”,不等于能访问具体数据库。
- 必须严格匹配
'user'@'host'全称,单引号不可省略;host 部分若含通配符(如'%'、'10.20.%')也要原样写入 - 普通用户执行该命令查他人权限会报错:
ERROR 1045 (28000): Access denied for user ... to database 'mysql',需具备SELECT权限或GRANT OPTION - 如果用户启用了角色,
SHOW GRANTS FOR默认会展开角色内含的权限(前提是角色已激活),无需额外操作
CURRENT_USER() 和 USER() 不一致时,权限归属以哪个为准?
你登录时用的是 mysql -u admin -h 192.168.1.100 -p,但 SHOW GRANTS 显示的权限可能和预期不符——大概率是 CURRENT_USER() 匹配到了另一个 'admin'@'%' 或 'admin'@'192.168.%' 账户。
验证方法很简单:
SELECT USER(), CURRENT_USER();
输出类似 'admin'@'192.168.1.100' 和 'admin'@'%',说明 MySQL 实际按 host 通配规则选中了后者。这时你要查的权限就是 'admin'@'%' 的,不是你“以为”的那个。
-
SHOW GRANTS;等价于SHOW GRANTS FOR CURRENT_USER();,永远不看USER() - 想强制查你声明的账号?得手拼:
SHOW GRANTS FOR 'admin'@'192.168.1.100';,但同样受权限限制 - 多个同名不同 host 的账户共存很常见,删冗余记录前务必先确认
CURRENT_USER(),否则可能误删正在用的权限
看到 USAGE 就代表没权限?不一定
GRANT USAGE ON *.* TO 'app_user'@'10.20.%' 这条输出常被误解为“完全没权限”,其实它只说明该用户没有全局权限,但完全可能拥有库级或表级权限。
例如用户被授予了 SELECT 在 orders 库下所有表,mysql.user 里对应字段仍是 N,SHOW GRANTS 却会明确列出:GRANT SELECT ON `orders`.* TO 'app_user'@'10.20.%'。
- 只要输出里有非
USAGE的GRANT ... ON行,就说明有实际权限 -
USAGE后面若带WITH MAX_QUERIES_PER_HOUR 100等资源限制,说明该账户是受控使用的业务账号,不是空壳 - 别跳过
ON后面的范围——ON *.*是全局,ON `db1`.*是库级,ON `db2`.`t1`是表级,粒度差异极大
批量导出所有用户的权限清单,不能只靠一条 SQL
MySQL 没有内置命令一键导出全部用户权限。硬拼 SELECT 多张系统表(mysql.user + mysql.db + mysql.tables_priv + information_schema.role_edges)不仅逻辑复杂,还会因字段加密(如 mysql.tables_priv.Table_name 是 base64)、角色未启用、动态权限缺失等问题导致结果失真。
真正可行的做法是脚本化调用 SHOW GRANTS FOR:
- 先提取所有有效账户:
SELECT DISTINCT CONCAT('''', User, '''@''', Host, '''') FROM mysql.user; - 对每个结果执行
SHOW GRANTS FOR ...,重定向到文件(注意连接用户需有足够权限) - 若环境不允许脚本,至少手动跑一遍
SELECT User, Host FROM mysql.user;,再逐个验证CURRENT_USER()是否与预期一致
最易被忽略的一点:角色权限是否启用,取决于会话上下文。即使用户被赋予了角色,若未执行 SET ROLE role_name; 或 SET DEFAULT ROLE,SHOW GRANTS 就不会展开——所以查权限时,最好在目标用户身份下连入后执行,而非用高权限账号代查。


















