SHOW GRANTS命令查看MySQL用户权限清单

作者:技术拾光

时间:2026-05-19

浏览:177

SHOWGRANTS命令仅显示用户被显式授予的权限,不包含通过角色继承、系统表隐式存储或缓存未刷新的权限。要获取用户真实有效的权限,需结合查询mysql.user、mysql.db等系统表,并检查角色绑定关系与权限缓存状态。权限排查需核对全局、库级及角色权限等多个来源。

文章目录

MySQL权限排查:为什么SHOW GRANTS显示的,不一定是用户真实拥有的?

排查MySQL用户权限时,SHOW GRANTS通常是第一选择。但你是否遇到过这种情况:明明确认给用户授权了,SHOW GRANTS也显示了相应语句,可用户实际操作时,却依然报“权限不足”?

问题根源在于:SHOW GRANTS命令展示的,仅仅是用户被显式授予的权限语句。它就像一个“授权记录本”,只记录了你亲手写下的条目。而那些通过角色继承、系统表隐式存储,甚至因为缓存未刷新而未生效的权限,它并不会主动显示。

SHOW GRANTS仅显示显式授予的权限,不包含角色继承、隐式权限或缓存未刷新导致的权限差异,需结合mysql.user、mysql.db、mysql.role_edges等系统表及FLUSH PRIVILEGES确认真实权限。

SHOW GRANTS命令查看MySQL用户权限清单

SHOW GRANTS 为什么只显示部分权限

执行 SHOW GRANTS FOR 'username'@'host' 时,返回的只是该用户「显式授予」的权限语句,它不包含通过角色继承来的权限——这在MySQL 8.0+启用角色功能后尤为常见。例如,用户被赋予了 analyst 角色,但如果当前会话没有执行 SET ROLE 'analyst' 来激活角色,那么角色里定义的 SELECT、EXECUTE 等权限,就不会出现在 SHOW GRANTS 的输出里。

这就解释了常见的困惑:你明明确认已经给用户绑定了角色,SHOW GRANTS 却看不到对应的库表权限。这大概率不是授权失败了,而是角色未激活,或者你没有去查 mysql.role_edges 这张表来确认绑定关系。

使用这个命令时,还有几个细节值得注意:

  • 格式必须严格匹配:'username'@'host' 是一个整体。别小看这个细节,'user'@'localhost' 和 'user'@'127.0.0.1' 在MySQL看来,是两个完全不同的账号。
  • 账号不存在?:如果遇到 ERROR 1141 (42000): There is no such grant defined for user 错误,先别急着下结论。最好执行 SELECT User, Host FROM mysql.user; 看看,确认一下这个账号到底是以什么“身份”注册的。
  • 自身权限限制:如果你自己没有 SELECT 权限去访问 mysql 系统库,那么执行 SHOW GRANTS FOR ... 指定用户时会直接失败。不过,SHOW GRANTS(不带参数,查看当前用户权限)通常还是可以用的。

如何查清用户实际权限:全局+库级+角色权限三合一

因此,单靠 SHOW GRANTS 很容易误判,尤其是在权限来源分散时。一个用户的真实生效权限,往往是多个来源的并集:mysql.user 表存放全局权限,mysql.db 表存放库级权限,mysql.role_edges 表则记录了角色绑定关系。

想要全面了解,推荐下面这个组合查询(执行需要访问这些系统表的权限):

SELECT
  u.User, u.Host,
  u.Select_priv AS global_select,
  d.Db, d.Select_priv AS db_select,
  r.Role, r.From_host
FROM mysql.user u
LEFT JOIN mysql.db d ON u.User = d.User AND u.Host = d.Host
LEFT JOIN mysql.role_edges r ON u.User = r.To_user AND u.Host = r.To_host
WHERE u.User = 'app' AND u.Host = '%';

解读查询结果的关键点:

  • 如果 global_select = 'Y',意味着用户拥有全局的 SELECT 权限,可以查询任意数据库。而 db_select = 'Y' 则说明,用户仅对 d.Db 列对应的那个特定数据库有查询权。
  • 如果 r.Role 字段不为空,那就说明这个用户绑定了角色。接下来,你需要进一步去查 mysql.roles_mapping,或者直接执行 SHOW GRANTS FOR ROLE 'xxx' 来搞清楚这个角色具体带了哪些权限。
  • 最后,别忘了确认是否执行过 FLUSH PRIVILEGES。如果没有,内存中的权限缓存可能还是旧的,磁盘上的配置修改并未真正生效。

mysqlshow:最轻量的权限试探工具

如果觉得查系统表太麻烦,或者想快速验证权限边界,mysqlshow 这个命令行工具是个不错的选择。它本质上就是用目标用户的身份,去尝试执行 SHOW DATABASES 和 SHOW TABLES,能比写SQL更快地暴露问题。

例如,执行:

mysqlshow -u app -p -h 10.0.1.5

观察输出,就能快速定位:

  • 如果直接报 Access denied for user 'app'@'10.0.1.5':这说明连认证阶段都没通过,可能是密码错误,或者host地址根本不在授权范围内。
  • 如果能列出数据库列表,但进入某个具体库时报 ERROR 1142 (42000): SHOW command denied:这说明用户有连接和访问该库的权限,但缺少执行 SHOW 命令(如 SHOW VIEW)或对该库内对象的 SELECT 权限。
  • 如果能进入库,但 SHOW TABLES 返回空:这可能是因为表名大小写不匹配(比如在 lower_case_table_names=0 的Linux环境下,授权时用了 USERS,但实际表是 users),或者权限只授予了视图,而没有授予底层基表。

权限“看得见却用不了”的典型原因

最让人头疼的情况莫过于此:SHOW GRANTS 明明白白显示着 SELECT ON mydb.*,可执行 SELECT * FROM mydb.users 时,系统依然无情地返回了错误。

问题的关键,往往不在于授权语句本身,而在于权限生效的上下文和约束条件:

  • 库级权限缺失:用户可能拥有全局的 SELECT 权限,但目标库 mydb 却没有出现在该用户的 mysql.db 记录中。在某些严格的权限模型下,这可能导致操作失败。
  • 大小写敏感陷阱:授权时写的是 USERS,但应用程序或查询中写的是 users。在Linux等默认大小写敏感的系统上,MySQL会认为这是两个不同的对象。
  • 依赖对象权限不足:查询可能涉及视图、存储过程或函数。即使用户对视图有 SELECT 权,但如果缺少底层基表的 SELECT 权限,或者缺少执行函数的 EXECUTE 权限,操作照样会失败。
  • SQL模式的影响:如果启用了 sql_mode=STRICT_TRANS_TABLES 等严格模式,MySQL会对权限和数据类型进行更苛刻的校验,可能触发在宽松模式下不会出现的错误。

说到底,MySQL权限排查就像剥洋葱。卡住你的地方,往往不是“有没有”权限这个简单的是非题,而是“权限的作用域是否精确覆盖了当前的操作路径”。SHOW GRANTS 只是一个起点,要看清全貌,你得顺着 mysql.user → mysql.db → mysql.tables_priv → mysql.role_edges 这条链,一层层地核对生效范围。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章