M部分权限的撤销
关于 MySQL 8.0.16 及以上版本中引入的 partial_revokes
功能,它允许管理员在拥有“全局权限”(如 GRANT SELECT ON *.*
)的基础上,对某些特定数据库(schema)进行部分权限的撤销,从而实现更细粒度的权限控制。
🔍 一句话总结
partial_revokes
让你可以“授予所有数据库的权限,但排除几个关键数据库”,比如:允许用户操作所有库,但不能动mysql
系统库。
🧩 为什么需要这个功能?
在 MySQL 8.0.16 之前:
- 如果你给一个用户授予了全局权限(
ON *.*
),就无法再针对某个具体数据库收回其中的一部分权限。 - 比如:
GRANT SELECT, INSERT ON *.* TO u1;
—— 你就不能单独“禁止 u1 在world
库中 INSERT”。
这就导致两种选择都很麻烦:
方式 | 缺点 |
---|---|
授予全局权限 | 无法限制敏感库(如 mysql , information_schema ) |
只授特定库权限 | 每新增一个库,都要手动加一次授权,维护成本高 |
而 partial_revokes
解决了这个问题:先全局授权,再局部收回某些权限。
✅ 如何使用 partial_revokes?
1. 启用 partial_revokes
默认是关闭的,必须手动开启:
SET PERSIST partial_revokes = ON;
PERSIST
表示重启后仍然生效。也可以用SET GLOBAL partial_revokes = ON;
仅本次有效。
2. 示例:全局授权 + 局部禁止 INSERT
-- 创建用户
CREATE USER u1;-- 全局授权
GRANT SELECT, INSERT ON *.* TO u1;-- 尝试部分收回(如果不启用 partial_revokes,会报错)
REVOKE INSERT ON world.* FROM u1;
✅ 成功后,u1
的权限是:
- 所有数据库:可
SELECT
,INSERT
- 除了
world
数据库:只能 SELECT,不能 INSERT
3. 查看权限(SHOW GRANTS)
SHOW GRANTS FOR u1;
输出:
+------------------------------------------+
| Grants for u1@% |
+------------------------------------------+
| GRANT SELECT, INSERT ON *.* TO `u1`@`%` |
| REVOKE INSERT ON `world`.* FROM `u1`@`%` |
+------------------------------------------+
注意:
REVOKE
语句也会显示出来,表示这是一个“部分限制”。
4. 内部存储位置
这些限制信息会保存在系统表 mysql.user
的 User_attributes
字段中(JSON 格式):
SELECT User, Host, User_attributes->>'$.Restrictions'
FROM mysql.user
WHERE User_attributes->>'$.Restrictions' <> '';
输出示例:
[{"Database": "world", "Privileges": ["INSERT"]}]
⚠️ 使用限制与注意事项
(1)只能用于 schema 级别的权限
不能用于:
- 全局权限(如
FILE
,SUPER
,BINLOG_ADMIN
) - 表、列、存储过程级别的权限
✅ 仅支持:SELECT
, INSERT
, UPDATE
, DELETE
, CREATE
, DROP
等可以在 ON db.*
上使用的权限。
(2)不能禁用 partial_revokes
如果已有用户受限
一旦有人用了 partial revoke,就不能直接关掉 partial_revokes
,否则会报错。
要关闭,必须先:
- 删除所有 partial revoke(通过再次授权或删除用户)
- 或者用
GRANT
把权限补回来
例如:
-- 移除对 world.* 的 INSERT 限制
GRANT INSERT ON world.* TO u1;
或者:
-- 再次全局授权,覆盖限制
GRANT INSERT ON *.* TO u1;
(3)权限继承规则(GRANT OPTION 场景)
如果用户 A 有部分权限被限制,并且有 WITH GRANT OPTION
,当他把权限转授给其他人时:
接收者情况 | 是否继承限制? |
---|---|
原本没有该权限 | ✅ 继承限制 |
已经有该权限(无限制) | ❌ 不继承,保留原有完整权限 |
👉 也就是说:GRANT 不会削弱已有权限,只会增强。
(4)新建 schema 的权限策略对比
策略 | 特点 | 适用场景 |
---|---|---|
只授特定库权限 (不启用 partial_revokes) | 新建库默认不可访问,需手动授权 | 用户只访问少数几个库 |
全局授权 + partial revoke (启用 partial_revokes) | 新建库自动可访问,只需为敏感库加限制 | 用户需要访问大多数库,仅排除少数 |
✅ 所以:如果你有很多业务库,想让运维/开发通用账号访问所有业务库但不能碰系统库,用 partial_revokes 更方便。
(5)通配符 _
和 %
的处理变化
启用 partial_revokes
后,MySQL 会把未转义的 _
和 %
当作字面字符处理,而不是通配符。
⚠️ 所以建议:
- 避免在数据库名中使用
_
或%
- 如果必须用,记得转义:
\_
,\%
(6)复制(Replication)要求
在主从复制环境中:
- 所有节点(主库和从库)都必须启用
partial_revokes
- 否则
REVOKE ... ON db.*
在从库上可能失败,导致复制中断
此外,GRANT
语句的 binlog 中会记录:
- 是谁执行的
- 当前激活的角色
所以要确保:
- 所有执行
GRANT
的用户在从库上也存在 - 角色配置一致
否则复制线程会报错停止。
💡 实际应用场景举例
场景:保护 mysql
系统库
你想让 DBA 账号可以管理所有业务库,但绝对不能修改 mysql.user
表。
CREATE USER 'dba_common'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'dba_common'@'%' WITH GRANT OPTION;-- 禁止其修改 mysql 系统库
REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM 'dba_common'@'%';
现在这个用户:
- 可以查看
mysql.user
(因为SELECT
没被收回) - 但不能插入、更新、删除任何系统表
🔐 这是一种“最小权限原则”的实践。
🛑 如何删除 partial revoke?
有三种方式可以“取消”一个 partial revoke:
方法 1:重新全局授权(最直接)
GRANT INSERT ON *.* TO u1;
这会移除所有
INSERT
相关的限制。
方法 2:在受限库上重新授权
GRANT INSERT ON world.* TO u1;
这样用户在
world
库又有INSERT
权限,限制被覆盖。
方法 3:完全撤销该权限(慎用)
REVOKE INSERT ON *.* FROM u1;
这会彻底删除
INSERT
权限,包括所有库。
📚 总结:核心要点
要点 | 说明 |
---|---|
✅ 引入版本 | MySQL 8.0.16 |
✅ 控制变量 | partial_revokes = ON (默认 OFF) |
✅ 功能 | 允许“全局授权 + 局部收回”某些权限 |
✅ 典型用途 | 保护 mysql 、performance_schema 等系统库 |
❌ 限制 | 不能用于全局权限(如 FILE)、不能用于表/列级 |
⚠️ 复制要求 | 所有节点必须同时启用 partial_revokes |
⚠️ 权限继承 | GRANT 时,已有权限不会被削弱 |
💡 优势 | 适合“广泛访问 + 少数排除”的场景,减少维护成本 |
🧭 建议使用策略
用户类型 | 推荐方案 |
---|---|
普通应用账号(只访问1~2个库) | ❌ 不启用 partial_revokes,直接授具体库权限 |
运维/DBA 账号(访问大部分库) | ✅ 启用 partial_revokes,全局授权 + 排除系统库 |
审计账号(只读所有库) | ✅ 可用:GRANT SELECT ON *.* + REVOKE SELECT ON mysql.* |
如有具体使用场景,我可以帮你设计权限模型。