mysql中访问控制列表(ACL)与权限模型

来源:这里教程网 时间:2026-02-28 20:43:04 作者:

MySQL 的权限存储在哪张表里

MySQL 的 ACL(Access Control List)信息全部存放在

mysql
系统数据库的几张核心表中,不是内存结构或配置文件。主要涉及:
user
db
tables_priv
columns_priv
procs_priv
proxies_priv

其中最常用的是:

user
:控制全局级别权限(如
SELECT
CREATE USER
)和连接参数(如
max_connections
db
:控制某个数据库级别的权限(如对
myapp
库的
INSERT
tables_priv
columns_priv
:细化到表或列的权限,实际生产中极少手动操作,多通过
GRANT
语句间接写入

直接

UPDATE
这些表不会立即生效——必须执行
FLUSH PRIVILEGES
才能重载,否则新权限不被识别。

GRANT 和 INSERT INTO mysql.user 的区别

GRANT
创建用户并赋权,是 MySQL 推荐且安全的方式;而直接
INSERT INTO mysql.user
是绕过校验的“硬写”,容易出错。

关键差异:

GRANT
会自动哈希密码(如果使用
IDENTIFIED BY
)、检查语法、填充默认权限字段(如
ssl_type
account_locked
),并隐式触发权限重载
手动
INSERT
必须自己设置
authentication_string
(不是
password
字段,5.7+ 已废弃)、
plugin
(通常是
caching_sha2_password
mysql_native_password
),漏掉
account_locked
password_expired
可能导致用户无法登录
GRANT ... ON *.*
写入
user
表;
GRANT ... ON db.*
写入
db
表;但直接
INSERT
不会自动关联
db
表,权限粒度会错位

例如,以下语句看似等价,实则风险不同:

GRANT SELECT ON mydb.* TO 'appuser'@'10.0.1.%' IDENTIFIED BY 'pwd123';

vs

INSERT INTO mysql.user (Host, User, authentication_string, plugin) VALUES ('10.0.1.%', 'appuser', PASSWORD('pwd123'), 'mysql_native_password');

后者没设

Select_priv = 'Y'
,也没插入
db
表记录,用户创建成功但无任何权限。

权限生效顺序与拒绝优先级

MySQL 权限按层级叠加,但“拒绝”(

DENY
)在 8.0+ 才支持,且只在企业版或 8.0.16+ 社区版通过
REVOKE
+
WITH ADMIN OPTION
间接体现;标准社区版没有显式
DENY
机制。

权限判断逻辑是“匹配最长 Host/User + 最高粒度”,顺序固定为:

先查
user
表(全局)→ 匹配
Host
User
,满足则用该行权限
若全局无匹配,再查
db
表 → 要求
Host
User
Db
全部匹配
再往下是
tables_priv
columns_priv
,逐级细化

注意:

user
表中某权限字段为
'N'
,不代表“拒绝”,只是“未授予”。MySQL 没有 deny-by-default 模式,所有未显式授予的权限默认不可用。

一个常见陷阱:

user
表里
Select_priv = 'Y'
,但
db
表里同用户对某库
Select_priv = 'N'
—— 实际仍可查(因为全局权限覆盖库级)。只有当全局为
'N'
,才继续下探。

FLUSH PRIVILEGES 什么时候必须执行

仅在**直接修改

mysql
系统表**后才需要
FLUSH PRIVILEGES
;用
GRANT
CREATE USER
DROP USER
等 DDL 语句操作时,MySQL 自动重载权限缓存,无需手动刷新。

误用

FLUSH PRIVILEGES
的后果:

它强制重载全部权限数据,对高并发实例可能造成短暂锁表(尤其是
user
表)
如果此时系统表有损坏或格式错误(比如
authentication_string
值非法),会导致整个权限系统不可用,连
root
都可能无法登录
在 MySQL 8.0+,部分字段(如
password_last_changed
)由内部机制维护,手动
FLUSH
可能干扰其状态

所以,除非你明确改了

mysql.user
mysql.db
的行,否则不要碰
FLUSH PRIVILEGES
。很多线上故障就源于运维脚本里无脑加这一句。

相关推荐