MySQL表级权限必须用GRANT指定db_name.table_name格式,如GRANT SELECT,UPDATE ON sales.orders TO 'app_user'@'localhost';SHOW GRANTS默认不显示表权限,需查mysql.tables_priv确认。

GRANT 语句怎么写才能只给某张表的权限
MySQL 表级权限必须通过 GRANT 显式指定数据库名和表名,不能只写表名。常见错误是漏掉 db_name.table_name 格式,导致权限被误授到整个库或失败。
正确写法示例(授予用户 app_user 对 sales 库中 orders 表的查询和更新权限):
GRANT SELECT, UPDATE ON sales.orders TO 'app_user'@'localhost';
- 必须包含数据库名前缀,
orders单独写会报错ERROR 1144 (42000): Wildcard denied for table - 权限类型(如
SELECT、INSERT)不支持列级限制,除非额外加(col1, col2)括号限定字段 - 执行后需运行
FLUSH PRIVILEGES;(仅当直接修改mysql.tables_priv表时才强制需要;用GRANT通常自动生效)
为什么 SHOW GRANTS 看不到刚授的表权限
因为 SHOW GRANTS FOR 'user'@'host' 默认只显示全局和库级权限,表级权限默认隐藏——这是 MySQL 的显示策略,不是没生效。
要确认表权限是否写入,查系统表:
SELECT * FROM mysql.tables_priv WHERE User='app_user' AND Host='localhost' AND Db='sales' AND Table_name='orders'\G
-
tables_priv表中Table_priv字段是逗号分隔的权限字符串,如Select,Update - 如果该行不存在,说明
GRANT未成功执行(常见于用户不存在、SQL 语法错误、或当前会话无GRANT OPTION) - 注意:MySQL 8.0+ 中视图
information_schema.role_table_grants不包含普通用户的表级授权,仍得查mysql.tables_priv
REVOKE 表权限时容易遗漏的关键点
撤销表级权限不能只写 REVOKE SELECT ON orders...,必须和授权时完全一致——包括数据库名、表名、用户主机段。
- 错误写法:
REVOKE SELECT ON orders FROM 'app_user'@'%';→ 报错ERROR 1147 (42000): There is no such grant defined for user - 正确写法:
REVOKE SELECT ON sales.orders FROM 'app_user'@'localhost'; - 如果当初授权用了通配符(如
sales.o%),撤销时也得用同样模式,否则匹配不上 - 撤销后不会自动清理
mysql.tables_priv空行,可能残留''权限字段,建议查表确认
MySQL 8.0+ 中角色(ROLE)能否简化表权限管理
可以,但角色本身不直接拥有表权限,它只是权限容器;你仍需对角色执行带库表前缀的 GRANT,再把角色赋予用户。
例如:
CREATE ROLE 'sales_analyst';<br>GRANT SELECT ON sales.orders TO 'sales_analyst';<br>GRANT 'sales_analyst' TO 'ana_user'@'10.%.%.%';
- 角色不能跨库继承表权限,
GRANT SELECT ON *.orders是非法语法 - 用户激活角色后(
SET ROLE 'sales_analyst';),才获得对应表权限;默认不自动激活 - 权限检查路径变长(用户 → 角色 → tables_priv),高并发下有微小性能开销,但对绝大多数业务无感
真正容易被忽略的是:表权限不支持存储过程内动态生效——哪怕用户有 EXECUTE 权限,过程中访问表仍受其自身表级权限约束,不会因过程定义者权限而提升。










