error 1049 (42000): unknown database 是因 grant 语句中指定的数据库不存在,mysql 在权限校验前强制验证库存在性;需先执行 create database if not exists mydb; 再运行 grant。

GRANT 语句报错 ERROR 1049 (42000): Unknown database
这个错误不是权限问题,而是 MySQL 在执行 GRANT 前会先校验目标数据库是否存在。如果 GRANT ALL ON mydb.* TO ... 中的 mydb 根本没创建,就会直接报错,根本不会走到权限检查阶段。
常见触发场景:
- 脚本中先写
GRANT再写CREATE DATABASE,顺序反了 - 数据库名拼写错误,比如把
app_prod写成app_pro - 连接时默认选了别的库(比如
mysql),但GRANT语句里写的库名又不存在,MySQL 不会自动切换上下文去查
解决办法很简单:先确认库存在。运行 SHOW DATABASES;,再执行 CREATE DATABASE IF NOT EXISTS mydb;,之后再跑 GRANT。
GRANT ... ON table_name 报 ERROR 1146 (42S02): Table doesn't exist
MySQL 的 GRANT 语句不支持对单个表授予权限,除非该表已经存在且在指定数据库中。也就是说,GRANT SELECT ON mydb.users TO 'u'@'%'; 要求 mydb 库下必须已有 users 表——哪怕只是空表。
原因在于:GRANT 的表级权限是绑定到具体表对象的元数据上的,不是逻辑名称。MySQL 会去 information_schema.tables 查这个表是否真实存在。
如果你还没建表就急着授权,会出现两种选择:
- 先建表:用
CREATE TABLE mydb.users (...);占位,哪怕只有 1 列;授权后再改结构 - 改用数据库级授权:
GRANT SELECT ON mydb.* TO 'u'@'%';,这样不依赖具体表是否存在
注意:GRANT ... ON *.* 或 ON db.* 是安全的,它们只校验库是否存在,不查表。
用户登录后 SHOW DATABASES 看不到刚授权的库
这不是授权失败,而是 MySQL 的“可见性”机制在起作用:即使你给用户授予了某个库的全部权限,只要没显式执行过 USE database_name 或该库名不在用户默认连接参数里,SHOW DATABASES 默认只会列出用户有 USAGE 权限(即能连接)或明确被授予过权限的库——但前提是这些权限已生效且未被更细粒度的权限覆盖。
更关键的是:权限缓存。执行 GRANT 后必须跟 FLUSH PRIVILEGES;,否则新权限不会立刻加载进内存。很多自动化脚本漏掉这步,导致看起来“授权了却看不到”。
验证方式:
- 用该用户重新登录(断开重连),再执行
SHOW DATABASES; - 或者登录后直接
USE mydb;—— 如果能切进去,说明权限实际已生效,只是SHOW DATABASES的过滤逻辑让它没显示 - 检查是否被
REVOKE过其他权限,比如不小心执行了REVOKE ALL ON *.* FROM 'u'@'%';,会清空所有库的可见性
为什么 GRANT 里用了反引号还是报找不到?
反引号(`)只能解决标识符含特殊字符或关键字的问题,比如库名是 `order` 或 `my-db`,但它不能绕过“库/表物理不存在”这个硬性校验。
典型误用:
-
GRANT SELECT ON `nonexistent_db`.`t` TO 'u'@'%';→ 依然报Unknown database -
GRANT SELECT ON `mydb`.`nonexistent_table` TO 'u'@'%';→ 依然报Table doesn't exist
反引号唯一能帮上忙的,是避免语法解析错误,比如库名含短横线、空格或叫 select 这类保留字。但它不等于“忽略存在性检查”。
真正容易被忽略的一点:MySQL 8.0+ 默认启用 sql_require_primary_key 等严格模式,但这个不影响 GRANT 校验;真正影响的是 skip-name-resolve 配置——如果开启且 host 写的是域名而非 IP,而 DNS 解析失败,GRANT 可能因无法确认 'u'@'host' 的 host 部分而行为异常,间接导致权限未正确绑定。











