最直接查库级UPDATE权限用INFORMATION_SCHEMA.SCHEMA_PRIVILEGES,但需结合ROLE_TABLE_GRANTS、TABLE_PRIVILEGES、COLUMN_PRIVILEGES及SHOW GRANTS综合验证,因权限可能来自角色继承、表/列级授权、PROXY或DEFINER机制。

查哪些用户有 UPDATE 权限:直接读 INFORMATION_SCHEMA.ROLE_TABLE_GRANTS 或 INFORMATION_SCHEMA.SCHEMA_PRIVILEGES
MySQL 8.0+ 默认启用角色和细粒度权限模型,INFORMATION_SCHEMA.SCHEMA_PRIVILEGES 是最直接的入口——它按数据库粒度列出谁对哪个库有哪种权限。但注意:它只反映显式授予的库级权限(比如 GRANT UPDATE ON mydb.*),不包含表级、列级或通过角色间接获得的权限。
实操建议:
- 用
SELECT GRANTEE, PRIVILEGE_TYPE, IS_GRANTABLE FROM INFORMATION_SCHEMA.SCHEMA_PRIVILEGES WHERE PRIVILEGE_TYPE = 'UPDATE'快速筛出有库级 UPDATE 权的账号 -
GRANTEE字段格式是'user'@'host',记得用TRIM或正则处理引号,避免匹配失败 - 如果启用了角色(
show variables like 'activate_all_roles_on_login'为 ON),还要查ROLE_TABLE_GRANTS并关联APPLICABLE_ROLES,否则会漏掉角色继承来的权限
查具体某张表的 UPDATE 权限:盯紧 TABLE_PRIVILEGES 和 COLUMN_PRIVILEGES
库级权限只是冰山一角。真正决定“能不能改某行数据”的,往往是表级甚至列级授权。比如 GRANT UPDATE(col_a) ON mydb.t1 这种限制性授权,只在 COLUMN_PRIVILEGES 里体现。
常见错误现象:执行 UPDATE t1 SET col_b=1 报错 ERROR 1142 (42000): UPDATE command denied,但查 SCHEMA_PRIVILEGES 显示有权限——大概率是权限只给了特定列,或者只给了某张表。
实操建议:
- 先查表级:
SELECT GRANTEE, TABLE_NAME, PRIVILEGE_TYPE FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't1' AND PRIVILEGE_TYPE = 'UPDATE' - 再查列级:
SELECT GRANTEE, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't1' AND PRIVILEGE_TYPE = 'UPDATE' - 注意
TABLE_PRIVILEGES中的GRANTEE可能是角色名(如'app_role'@'%'),需结合ROLE_ROUTINE_GRANTS或ADMINISTRABLE_ROLE_AUTHORIZATIONS追踪实际持有者
为什么 SHOW GRANTS FOR user 比查 INFORMATION_SCHEMA 更可靠?
SHOW GRANTS 返回的是 MySQL 实际生效的权限集合,自动合并了直接授权、角色继承、代理权限(PROXY)等所有路径。而 INFORMATION_SCHEMA 表是静态快照,不反映运行时权限计算逻辑,尤其在角色嵌套深、权限被 REVOKE 后未刷新缓存时容易失真。
性能与兼容性影响:
-
SHOW GRANTS是轻量命令,无锁、不扫描元数据表,适合运维脚本高频调用 - MySQL 5.7 不支持角色,
INFORMATION_SCHEMA.ROLE_*表不存在,但SHOW GRANTS全版本可用 - 如果要批量检查上百个用户,别用循环执行
SHOW GRANTS(网络开销大),改用SELECT user, host FROM mysql.user拼接后一次性查INFORMATION_SCHEMA,再用SHOW GRANTS抽样验证关键账号
容易被忽略的权限来源:Proxy 用户、SQL SECURITY DEFINER 函数、SET ROLE
一个用户看似没 UPDATE 权,却能成功修改数据,往往是因为绕过了常规权限检查。比如函数或存储过程以 SQL SECURITY DEFINER 定义,调用者借用了定义者的权限;或者用户被设为 proxy(GRANT PROXY ON 'admin'@'%' TO 'app'@'localhost'),实际执行时权限提升。
实操建议:
- 查 proxy 关系:
SELECT * FROM mysql.proxies_priv WHERE Host = 'your_host' AND User = 'your_user' - 查 DEFINER 函数:
SELECT name, definer FROM mysql.proc WHERE security_type = 'DEFINER' AND body LIKE '%UPDATE%' - 检查当前会话是否已切换角色:
SELECT CURRENT_ROLE(),因为SET ROLE后权限立即变化,但INFORMATION_SCHEMA不体现会话态
权限不是静态配置,而是运行时计算结果。查 INFORMATION_SCHEMA 只能当起点,最终以 SHOW GRANTS 和实际执行反馈为准。










