MySQL权限分层:全局权限(如ON .)跨库生效,数据库级权限(如ON mydb.*)仅限指定库;CREATE/DROP DATABASE等元数据操作必须授予全局权限;权限检查顺序为全局→数据库→表→列,高优先级覆盖低优先级。

全局权限能跨库操作,数据库级权限只能作用于指定库
MySQL 的权限体系是分层的,GRANT 语句中指定的权限作用域直接决定用户能做什么。全局权限(如 GRANT SELECT ON *.*)表示对所有现有和未来创建的数据库都生效;而数据库级权限(如 GRANT SELECT ON mydb.*)只在 mydb 这个库内有效,哪怕之后新建了 otherdb,该用户也无权访问。
CREATE DATABASE 权限必须在全局级别授予
即使你给用户授予了 mydb 的全部权限(GRANT ALL ON mydb.*),他依然不能执行 CREATE DATABASE otherdb。因为 CREATE DATABASE 是一个需要 CREATE 全局权限的操作——它不作用于某个具体库,而是影响服务器元数据。常见误操作是以为“有了库级 ALL 就能建库”,结果报错:ERROR 1044 (42000): Access denied for user ... to database 'otherdb'。
-
GRANT CREATE ON *.* TO 'u'@'%'✅ 允许创建任意新库 -
GRANT CREATE ON mydb.* TO 'u'@'%'❌ 不起作用,MySQL 忽略该授权 - 同理,
DROP DATABASE、SHOW DATABASES也都依赖全局权限
权限叠加时,全局权限优先级高于数据库级
如果一个用户同时拥有全局 SELECT 和某个库的 REVOKE SELECT,最终仍可查该库——因为全局权限未被显式收回,且覆盖更细粒度的拒绝。MySQL 权限检查顺序是:全局 → 数据库 → 表 → 列,只要某一层允许,就通过(除非被更上层显式拒绝)。这意味着:
- 撤销权限必须在相同作用域执行,
REVOKE SELECT ON mydb.*无法取消SELECT ON *.* -
SHOW GRANTS FOR 'u'@'%'返回的结果里,*.*条目会出现在mydb.*前面,反映检查顺序 - 用
FLUSH PRIVILEGES不解决权限不生效问题,真正生效靠的是权限表(mysql.user,mysql.db)的实时读取
mysqldump 备份时容易暴露权限设计缺陷
用 mysqldump --all-databases 要求用户有全局 SELECT 和 LOCK TABLES,但很多人只给了目标库权限,导致备份中途失败。更隐蔽的问题是:如果用户只有 mydb.* 权限,却尝试 mysqldump --databases mydb otherdb,MySQL 会拒绝导出 otherdb(即使它存在),并报错 Access denied for user ... to database 'otherdb' ——这不是连接问题,是权限校验在 dump 阶段逐库触发的。
mysqldump -u backup_user -p --databases mydb otherdb # 如果 backup_user 没有 otherdb.* 或 *.* 权限,这里就会中断
实际部署中,别默认“给库权限就够了”,先想清楚操作是否跨库、是否涉及元数据变更。权限最小化原则在这里特别容易被绕过,因为看起来只是“少建一个库”或“少导一个库”,背后其实是权限模型的层级刚性。










