MySQL表级权限必须使用db_name.table_name完整格式,省略库名会报ERROR 1144;用户须预先创建;SHOW GRANTS不显示表级权限,需查mysql.tables_priv确认。

GRANT SELECT ON db_name.table_name 语法必须带库名前缀
直接写 GRANT SELECT ON orders TO 'user'@'localhost' 会报错 ERROR 1144 (42000): Wildcard denied for table。MySQL 表级权限强制要求完整格式:database_name.table_name,不能省略数据库名。
常见错误是误以为像 USE db_name 后就能省略库名——实际不行,ON 子句里的作用域是静态解析的,和当前会话无关。
- 正确写法:
GRANT SELECT ON sales.orders TO 'app_reader'@'10.0.1.%' - 如果表名含特殊字符(如横线、空格),用反引号包裹:
GRANT SELECT ON `my-db`.`order-log` TO 'user'@'localhost' - 不要写成
sales.*或*.*,那会授予整个库或所有库权限,违背最小权限原则
SHOW GRANTS 看不到表权限?查 mysql.tables_priv 才准
SHOW GRANTS FOR 'user'@'host' 默认只显示全局(mysql.user)和库级(mysql.db)权限,表级权限藏在 mysql.tables_priv 表里,不会出现在输出中——这不是 bug,是 MySQL 的设计行为。
要确认权限是否真正写入,执行:
SELECT Table_priv, Column_priv FROM mysql.tables_priv WHERE User = 'app_reader' AND Host = '10.0.1.%' AND Db = 'sales' AND Table_name = 'orders'\G
返回结果中 Table_priv 是逗号分隔字符串,比如 Select 或 Select,Insert;为空或无结果行,说明 GRANT 没生效。
- 常见原因:用户不存在、SQL 语法错误、执行者没
GRANT OPTION权限 - MySQL 8.0+ 仍需查
mysql.tables_priv,information_schema.role_table_grants不包含普通用户的表级授权
CREATE USER 必须先执行(尤其 MySQL 8.0+)
MySQL 8.0 起,GRANT 不再自动创建用户。如果直接跑 GRANT SELECT ON sales.orders TO 'new_user'@'%' IDENTIFIED BY 'pwd',会报错 ERROR 1396 (HY000): Operation CREATE USER failed。
必须拆成两步:
- 先建用户:
CREATE USER 'new_user'@'%' IDENTIFIED BY 'StrongPass!2026' - 再授表权限:
GRANT SELECT ON sales.orders TO 'new_user'@'%'
注意:CREATE USER 中的主机名(%、localhost、具体 IP)必须和 GRANT 中的一致,否则权限不匹配——MySQL 把 'user'@'localhost' 和 'user'@'%' 视为两个完全不同的账户。
权限生效要不要 FLUSH PRIVILEGES?
用标准 GRANT 语句授予权限后,**通常不需要手动执行 FLUSH PRIVILEGES** ——MySQL 会自动刷新内存中的权限缓存。
只有当你绕过 GRANT、直接修改 mysql.tables_priv 等系统表时,才必须执行它。但这种操作极不推荐,容易引发权限状态不一致。
- 如果你执行了
FLUSH PRIVILEGES,不会出错,但属于冗余操作 - 真正该做的验证是:用新用户登录,执行
SELECT * FROM sales.orders LIMIT 1,看是否被拒绝或成功 - 如果连登录都失败,先检查用户是否存在、密码是否正确、主机名是否匹配,而不是怀疑权限没生效
表级权限配置最易忽略的点:权限对象必须严格匹配(库名+表名)、用户必须预先存在、SHOW GRANTS 不显示表级授权——这三个条件缺一不可,少一个都会让“明明写了 GRANT 却没效果”成为常态。











