SHOW GRANTS FOR角色必须显式带主机名,如'app_reader'@'%';仅显示直接授予的权限,不含继承或列级权限,需查mysql.role_edges或INFORMATION_SCHEMA.ROLE_COLUMN_GRANTS补全。

SHOW GRANTS FOR role_name@'%' 必须带主机名
MySQL 8.0 不把角色当“独立账户类型”处理,SHOW GRANTS FOR 仍按用户语法解析。直接写 SHOW GRANTS FOR 'app_reader' 会报错 ERROR 1141 (42000): There is no such grant defined for user 'app_reader' on host '%'——因为 MySQL 自动补全为 'app_reader'@'%',而角色默认创建时绑定的 host 就是 '%',但你得自己写出来。
正确写法只有这一种形式:
SHOW GRANTS FOR 'app_reader'@'%';
如果角色是用 CREATE ROLE 'admin'@'localhost' 创建的,那这里也必须严格匹配:SHOW GRANTS FOR 'admin'@'localhost'。大小写、引号、@ 和 host 都不能错。
查到的只是直接授予的权限,不含嵌套角色权限
SHOW GRANTS FOR 'app_reader'@'%' 返回的,仅限该角色被 GRANT ... TO 'app_reader'@'%' 显式赋予的权限,比如:
GRANT SELECT ON `sales`.* TO 'app_reader'@'%';
但如果 app_reader 还被另一个角色 base_reader 授予过(即 GRANT 'base_reader'@'%' TO 'app_reader'@'%'),这些继承来的权限**完全不会出现在输出里**。
- 这是最容易误判的一点:看到结果里没
INSERT,就以为角色不能写——其实它可能通过子角色获得 - 要查嵌套关系,得查
mysql.role_edges表:SELECT FROM_USER, FROM_HOST FROM mysql.role_edges WHERE TO_USER = 'app_reader' AND TO_HOST = '%' - 再对每个
FROM_USER单独执行SHOW GRANTS FOR才能拼出完整权限集
列级权限不会显示,需查 INFORMATION_SCHEMA.ROLE_COLUMN_GRANTS
如果你给角色授了类似 GRANT UPDATE(email) ON users.users TO 'app_writer'@'%' 这样的列级权限,SHOW GRANTS FOR 输出里**根本看不到**。MySQL 8.0.19+ 才把这类权限存进系统视图,低于该版本查不到。
确认版本后执行:
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, PRIVILEGE_TYPE FROM INFORMATION_SCHEMA.ROLE_COLUMN_GRANTS WHERE ROLE_NAME = 'app_writer' AND ROLE_HOST = '%';
注意:ROLE_COLUMN_GRANTS 视图在 8.0.19 之前不存在,运行会报错 Unknown table;且它只存列级权限,不包含库/表级。
权限不是静态快照,角色可能未激活或受限于当前上下文
SHOW GRANTS FOR 'role'@'%' 只反映“这个角色对象当前被授予了什么”,不等于它在任意会话中都能生效。实际使用还受两层限制:
- 角色是否已被用户激活:查
SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES;,空结果说明即使绑了角色也没启用 - 用户是否拥有该角色的
USAGE权限:若只被GRANT 'role'@'%' TO 'user'@'%'但没WITH ADMIN OPTION,用户无法自行SET ROLE - 某些动态权限(如
BACKUP_ADMIN)虽列在SHOW GRANTS中,但需配合SET PERSIST或服务重启才真正可用
最稳妥的做法是:先确认角色存在、有直接权限、无嵌套遗漏、列级权限已覆盖,再用目标用户登录,执行 SET ROLE 'role_name'@'%'; 后验证具体语句是否真能跑通——权限列表只是纸面声明,执行才是最终仲裁。


















