SHOW GRANTS FOR 'username'@'host' 是查看指定用户显式授权语句的最常用方式,需严格匹配主机名(如'localhost'与'%'不等价),MySQL 8.0+角色权限需额外查系统表或加USING子句。

用 SHOW GRANTS 查看指定用户的当前权限定义
直接执行 SHOW GRANTS FOR 'username'@'host' 是最常用方式,它返回该账号在 mysql.user 和权限表中被显式授予的语句(如 GRANT SELECT ON db.* TO ...)。注意:这不等于“实际生效权限”,只是授权记录的文本还原——比如用户有 SELECT 权限但所在角色被禁用,这里仍会显示。
常见错误是漏写主机名,导致报错 ERROR 1141 (42000): There is no such grant defined for user 'xxx' on host '%'。必须严格匹配创建账号时的 @ 后部分,包括 'localhost' 和 '127.0.0.1' 的区别。
- 若账号使用了角色(MySQL 8.0+),需额外查
SHOW GRANTS FOR 'username'@'host' USING role_name - 通配符主机如
'%'要加单引号,否则语法错误 - 结果里出现
WITH GRANT OPTION表示该用户能转授此权限,不是普通权限项
用 INFORMATION_SCHEMA.ROLE_TABLE_GRANTS 和 ROLE_COLUMN_GRANTS 检查角色继承的权限
MySQL 8.0 开始支持角色,权限可能来自角色而非直授。仅靠 SHOW GRANTS 会漏掉角色赋予的库表级权限。必须查系统表确认角色是否激活、权限是否被包含。
先确认用户启用的角色:SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES WHERE GRANTEE = "'username'@'host'";。再对每个角色查其权限:SELECT * FROM INFORMATION_SCHEMA.ROLE_TABLE_GRANTS WHERE ROLE_NAME = 'role_name';
- 角色未被
SET DEFAULT ROLE或SET ROLE激活时,其权限不生效,但系统表里仍存在记录 -
ROLE_COLUMN_GRANTS表用于列级权限,普通场景很少见,但若业务用了细粒度控制就得扫一遍 - 角色权限不会出现在
SHOW GRANTS主输出里,除非显式加上USING子句
用 SELECT 查询 mysql 系统库里的权限表验证实际存储状态
权限最终由 mysql.user、mysql.db、mysql.tables_priv 等表控制。绕过语法糖直接查这些表,能看清哪些权限字段为 'Y',避免因角色缓存或元数据未刷新导致的偏差。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
例如查全局权限:SELECT * FROM mysql.user WHERE User='username' AND Host='host';;查库级权限:SELECT * FROM mysql.db WHERE User='username' AND Host='host' AND Db='target_db';
-
mysql.user中的plugin字段为'auth_socket'或'unix_socket'时,密码字段无效,权限检查逻辑不同 - 修改过权限表后必须执行
FLUSH PRIVILEGES;,否则变更不生效——这是线上最常被忽略的一步 - 5.7 及以前版本没有角色表,所有权限都落在
user/db/tables_priv这三张表上
权限是否真正生效?用 SHOW GRANTS FOR CURRENT_USER() + 实际操作验证
CURRENT_USER() 返回服务器认证时实际匹配的账号(如 'user'@'192.168.1.%'),而 USER() 返回客户端声明的账号。很多权限问题根源在于两者不一致——比如用户从 localhost 登录却只被授予了 'user'@'%',此时 SHOW GRANTS FOR USER() 会报错,但 CURRENT_USER() 才是真实上下文。
最可靠的方式是切换到目标账号后执行 SHOW GRANTS FOR CURRENT_USER();,再尝试对应操作(如 SELECT * FROM target_db.table LIMIT 1;)。报错 ERROR 1142 (42000): SELECT command denied to user 就说明权限没覆盖到当前连接上下文。
- 代理用户(PROXY)场景下,
CURRENT_USER()返回被代理的账号,权限也按那个账号计算 - 即使所有表查询都显示权限为 Y,若数据库名含下划线或特殊字符,而 SQL 里没加反引号,也会因解析失败表现为“无权限”
- MySQL 8.0 默认开启
sql_mode=STRICT_TRANS_TABLES,某些权限缺失会在预处理阶段报错,而非执行时
权限链路比表面看到的长:账号定义 → 角色绑定 → 角色激活 → 表权限匹配 → 连接匹配 Host/User → SQL 解析上下文。少扫一个环节,就可能以为“给了权限却不生效”。










