MySQL权限分5级:全局→数据库→表→列→存储过程/函数,逐层匹配取交集而非叠加;各层对应mysql.user、mysql.db等系统表,检查时以最高层级授权为准。

MySQL权限到底分几级?不是“有无权限”,而是“在哪生效”
MySQL权限不是扁平的“能/不能”二选一,而是严格按作用域分层生效:全局 → 数据库 → 表 → 列 → 存储过程/函数。每一层权限都存在对应的系统表(mysql.user、mysql.db、mysql.tables_priv等),MySQL启动时加载进内存,**权限检查是逐层匹配、取交集而非叠加**——比如用户在user表有SELECT全局权,但在db表被显式拒绝该库的SELECT,那最终就查不了这个库。
全局权限(*.*)能干啥?哪些操作必须它?
全局权限写在mysql.user表里,用GRANT ... ON *.*授予。它们不针对具体数据库,而是管理类操作的“入场券”:
-
PROCESS:执行SHOW PROCESSLIST,查别人连接和正在跑的SQL——没它,连自己连接都看不到完整信息 -
SUPER:杀连接(KILL)、切主从(CHANGE MASTER TO)、动态改变量(SET GLOBAL)——开发环境常误开,生产务必收敛 -
REPLICATION SLAVE:仅用于从库拉binlog,主库账号绝不能给这个权限 -
SHUTDOWN:执行mysqladmin shutdown——等同于直接关实例,几乎不该分配 -
FILE:读写服务器文件(LOAD DATA INFILE/SELECT ... INTO OUTFILE)——可读/etc/passwd,高危
表级和列级权限怎么配才不踩坑?
表级(GRANT SELECT ON db.tbl)和列级(GRANT UPDATE(col1) ON db.tbl)权限存于mysql.tables_priv和mysql.columns_priv,但实际使用中容易掉进两个坑:
- 列级权限只对
UPDATE/SELECT/INSERT生效,DELETE或DROP这类行/对象级操作,**不认列权限**——哪怕你只授了col1的UPDATE,用户删整行照样成功 - 如果用户同时有全局
SELECT和某张表的SELECT,MySQL不会报错,但SHOW GRANTS只显示最高层级的授权语句(即*.*),**你根本看不出他其实被单独限制过某张表**——排查越权时得手动查mysql.db和mysql.tables_priv -
ALTER表结构需要CREATE+INSERT配合,单给ALTER无效;TRUNCATE TABLE本质是DROP+CREATE,所以依赖DROP权限,不是DELETE
角色(Role)真能替代手工赋权吗?
MySQL 8.0+原生支持CREATE ROLE,但要注意:角色本身不登录,只是权限容器,必须GRANT role_name TO user才能生效。它的价值不在“省事”,而在解耦:
- 运维组统一维护
role_readonly,所有只读账号都GRANT它,删权限只需改角色,不用遍历每个用户 - 但
REVOKE角色权限后,用户当前会话仍保留旧权限,**必须执行SET ROLE DEFAULT或重新登录才刷新**——自动化脚本里漏这步,权限回收就失效 - 5.7及更早版本没有角色,只能靠
mysql.proxies_priv模拟,但那是“代理用户”机制,和角色语义不同,别混用
mysql.user表一旦写错Super_priv='Y',整个实例就暴露;而mysql.db里一个Select_priv='N'可能让应用查不到数据却报错模糊。查权限永远从SHOW GRANTS FOR 'u'@'h'起步,再顺藤摸到对应系统表,别猜。










