show grants for 'username'@'host' 是查看用户实际权限的最直接命令,返回mysql生效的授权语句;权限分层存储于mysql.user、mysql.db、mysql.tables_priv等表,需按作用域下钻查询。
show grants 是最直接的权限快照
想立刻知道一个用户到底能干啥,show grants for 'username'@'host' 就是唯一该敲的命令——它不查表、不拼接、不推理,直接返回 mysql 实际生效的授权语句,和你当初执行的 grant 语句几乎一致。
- 必须写全
'username'@'host',漏掉@'host'会报错,MySQL 把'user'和'user'@'localhost'当作两个完全不同的账号 - 如果记不清 host,先用
SELECT user, host FROM mysql.user WHERE user = 'username';确认,常见坑是以为用户是'app'@'%',结果实际建的是'app'@'192.168.%' - 返回结果里带
WITH GRANT OPTION表示这人还能给别人授同样权限,不是“有权限”而是“有权放权”,生产环境要特别警觉
mysql.user 表只反映全局权限,别误当全集
SELECT * FROM mysql.user WHERE user = 'xxx'; 看起来很全,但其实只覆盖服务器级操作(比如 CREATE DATABASE、SHUTDOWN),对库、表、列的权限它一概不存——这些全在别的系统表里。
-
Select_priv、Insert_priv这类字段只控制能否在任意库上执行对应操作,不表示对某个具体库有权限;哪怕这里全是N,只要在mysql.db表里配了,照样能查指定数据库 - 直接
SELECT * FROM mysql.user查所有人,容易把root@localhost和root@%权限搞混,它们可能是两套完全不同的策略 - 修改
mysql.user表后必须执行FLUSH PRIVILEGES;才生效,但用GRANT/REVOKE就不用——这是手动改表和语法授权的根本区别
权限分层存储:db / tables_priv / columns_priv 各管一摊
MySQL 的权限不是扁平一张表,而是按作用域分层落库:mysql.db 管库级、mysql.tables_priv 管表级、mysql.columns_priv 管列级。查权限时得按需下钻,不能只盯一个表。
- 查某用户对
orders库的权限?用SELECT * FROM mysql.db WHERE User='u1' AND Host='%' AND Db='orders'; - 查某用户在
users表里能不能改email字段?得查mysql.columns_priv,且注意Column_name是小写存储,匹配时大小写敏感 -
tables_priv和columns_priv表里的权限是“叠加生效”的:比如INSERT在表级开了,又在某列上显式DENY,最终结果就是不能插那列——但 MySQL 不支持 DENY 语法,这种限制实际靠应用层或视图规避
Privileges 界面的权限树 ≠ 实际生效权限
很多 GUI 工具(如 phpMyAdmin、Navicat、ADB 控制台)展示的“权限树”是前端渲染的逻辑视图,它把不同层级权限强行拉平成勾选框,看起来直观,但掩盖了真实优先级和冲突规则。
- 树形界面常把
SELECT显示为“库 > 表 > 列”三级可选,但 MySQL 实际执行时只看最细粒度的匹配项:如果columns_priv里没设,就退到tables_priv;再没有,才看db;最后才是user表。GUI 很少体现这个 fallback 链路 - 有些工具把
USAGE权限(即“仅登录,无任何操作权限”)隐藏不显示,导致你以为用户“没权限”其实是“权限被清空”,而非“未授权” - 当你在界面里点“全选所有权限”,后台可能生成多条
GRANT语句,但其中部分权限(如FILE、PROCESS)需要 SUPER 权限才能授予,普通管理员点了也白点,还不会报错提示
权限树看着省事,但它不告诉你哪条权限来自 GRANT、哪条是继承自角色、哪条被 REVOKE 覆盖过——真要定位问题,还是得回到命令行,一层层 SHOW GRANTS 和查系统表。










