mysql不支持从*.*授权中排除系统表,因系统库(如mysql、information_schema)权限受内部强校验约束,普通revoke无法覆盖;可靠做法是显式列举业务库授权或使用8.0+角色机制管控。

MySQL 不支持直接“排除系统表”这种语法,GRANT 语句作用域最小是数据库(db.*)或表(db.table),而系统表(如 mysql、information_schema、performance_schema、sys)本身是独立数据库,不能用“跳过某几张表”的方式从 ALL PRIVILEGES ON *.* 中剔除。
为什么不能对 *.* 授权后单独 REVOKE 系统库权限
MySQL 的权限检查是“叠加生效”,但 REVOKE 只能撤销你明确 GRANT 过的权限。如果你执行了:
GRANT ALL ON *.* TO 'dba'@'%';
这条命令实际授予的是「所有数据库的所有对象」权限,包括 mysql 库——而 mysql 库的权限无法被普通 REVOKE 覆盖,因为:
-
mysql库属于全局管理库,其权限受更严格的内部校验约束 - 对
mysql.*执行REVOKE需要GRANT OPTION+ 已有对应权限,且 MySQL 8.0+ 默认禁止非 super 用户操作mysql库 - 即使成功
REVOKE,某些操作(如修改用户密码、创建用户)仍可能因隐式依赖系统表而失败
手动列举业务库名进行授权才是安全可行路径
DBA 需要全库权限但不碰系统库,唯一可靠做法是:只对明确列出的业务数据库授予权限,避开 mysql、information_schema 等前缀库。
实操建议如下:
- 先查出当前所有业务库:
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys'); - 对每个库逐条执行:
GRANT ALL ON `db_name`.* TO 'dba'@'%';(注意库名加反引号,防止含特殊字符出错) - 不要省略
FLUSH PRIVILEGES;,尤其在 MySQL 5.7 或未启用skip-grant-tables时必须刷新 - 若库名较多,可用 shell +
mysql -Nse生成批量语句,例如:mysql -u root -p -Nse "SELECT CONCAT('GRANT ALL ON `', SCHEMA_NAME, '`.* TO \"dba\"@\"%\";') FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql','information_schema','performance_schema','sys');" | mysql -u root -p
MySQL 8.0+ 下角色(ROLE)方式更可控
如果用的是 MySQL 8.0.16+,推荐用角色替代直授,避免每次增删库都要改用户权限:
- 创建角色:
CREATE ROLE 'business_dba'; - 给角色授业务库权限(同上,手动列库):
GRANT ALL ON `order_db`.* TO 'business_dba'; GRANT ALL ON `user_db`.* TO 'business_dba'; - 把角色赋予用户:
GRANT 'business_dba' TO 'dba'@'%'; - 启用角色(可设默认):
SET DEFAULT ROLE 'business_dba' TO 'dba'@'%';
后续新增业务库,只需给角色加权限,无需动用户本身;回收也只需 REVOKE 角色,不影响其他权限结构。
最容易被忽略的一点:哪怕你严格按库名列表授权,也要确认该用户没有被意外赋予 GRANT OPTION 权限——否则他可以通过自己创建的用户间接操作 mysql 库。检查命令是:SHOW GRANTS FOR 'dba'@'%';,确保输出里没有 WITH GRANT OPTION。











