报错中的表名默认在当前数据库下查找,user表仅存在于mysql系统库;若未执行USE mysql,MySQL会在默认库中找user表并误报权限错误。

报错里写的表名,到底在哪个库下?
看到 SELECT command denied to user 'u1'@'localhost' for table 'user',第一反应不该是“加权限”,而是确认这个 user 表你是不是真在对的库里面找。MySQL 的 user 表只存在于 mysql 系统库,而普通用户默认进不去——哪怕你执行的是 SELECT * FROM user;,只要没先 USE mysql;,MySQL 就会去当前默认库(比如 myapp)里找 user 表,然后报“没权限”,其实根本是“表不存在”,只是错误提示误导人。
- 先运行
SELECT DATABASE();看当前库名 - 再运行
USE mysql;切换过去,然后再试SELECT * FROM user; - 如果表名带库前缀(如
mydb.sys_d),要确保mydb这个库真实存在且你有访问权;库不存在时,MySQL 也统一报权限拒绝,不是“Unknown database”
权限到底缺在哪一级?
报错中的 for table 'sys_d' 是关键线索:它说明 MySQL 明确卡在“对这张表执行 SELECT”这一步,不是泛泛的“没登录权限”或“不能连库”。必须按“命令 + 对象”组合来查缺什么。
- 用 root 登录后执行
SHOW GRANTS FOR 'u1'@'localhost';(注意 host 必须完全一致,'u1'@'127.0.0.1'和'u1'@'localhost'是两个账号) - 检查输出里有没有
GRANT SELECT ON `mydb`.`sys_d`或更宽泛的GRANT SELECT ON `mydb`.* - 如果只有
USAGE ON *.*,说明这个用户连基本数据库操作权都没有;如果只有SELECT ON `mydb`.`orders`,但你要查的是sys_d,那就纯属对象不匹配
授予权限时容易踩的三个坑
GRANT 不是写完就生效,尤其在权限模型收紧的 MySQL 8.0+ 上,错一个字符、漏一步操作,都会让授权白做。
-
GRANT SELECT ON *.*不包含mysql库——系统库被显式排除,必须写成GRANT SELECT ON mysql.user - MySQL 8.0+ 禁止
GRANT SELECT ON mysql.*,必须精确到表,比如GRANT SELECT ON mysql.user、GRANT SELECT ON mysql.db分开授 - 执行完
GRANT后必须跟FLUSH PRIVILEGES;,否则权限缓存不更新;客户端也要断开重连,连接池或 CLI 历史会话不会自动 reload 权限
不是权限问题,也可能是 SQL 写错了
有些 SELECT command denied 报错,实际和权限无关,而是 SQL 语句本身触发了隐式权限检查。
- 语句里写了库名前缀,比如
SELECT * FROM old_db.users;,但old_db已被删掉——MySQL 不报 “Unknown database”,而是降级为“SELECT denied for table 'users'” - 视图定义里引用了其他库的表,而当前用户对那个库没有 SELECT 权限,查这个视图就会报错,哪怕你只对视图所在库有权限
- 用了
DEFINER的视图或存储过程,执行时会按定义者身份检查权限,而不是调用者;此时即使你有所有表权限,也会因 DEFINER 账号权限不足而失败
真正卡住的地方,往往不在“要不要授权”,而在“授权对象是否精准匹配报错里的库名、表名、host 名,以及这条 SQL 实际触达了哪些隐式依赖”。


















