跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

mysql如何实现细粒度的列权限控制_MySQL GRANT语法列控制

MySQL 8.0.16起才真正支持列级授权,5.7及更早版本仅语法兼容但无效;必须用GRANT ... ON db.tbl(col)显式指定列名,不支持通配符,且权限检查以最严格为准。 MySQL 8.0+ 才支持真正的列级授权 MySQL 5.7 及更早版本不支持对单列执行
GRANT
;所谓“列权限”只是语法上允许写,实际授权后仍无法生效——连接后执行对应列的
SELECT
会直接报
ERROR 1142 (42000): SELECT command denied
。只有 MySQL 8.0.16 起才真正实现列级权限检查,且必须用
GRANT ... ON database.table(column_name)
显式指定列名。 常见错误现象:
GRANT SELECT (name) ON test.users TO 'u1'@'%';
在 5.7 上能执行成功,但
u1
登录后
SELECT name FROM test.users
依然被拒绝。 确认版本:运行
SELECT VERSION();
,低于
8.0.16
的别折腾列授权 列名必须明确列出,不支持通配符(如
(*)
(name, *)
) 同一用户对同一张表可混合授予不同列的权限,例如:先授
SELECT (id, name)
,再授
UPDATE (email)
GRANT 语句里列名写错位置就完全失效 列权限只能在
ON
子句中、紧跟表名后用括号声明,不能放在
GRANT
动词后面,也不能塞进引号或变量里。写成
GRANT SELECT(name) ON test.users
是合法的;但
GRANT SELECT ON test.users(name)
GRANT SELECT (name) ON test.`users`
(反引号包表名但漏了列括号)都会被 MySQL 当作语法错误或降级为表级授权。 正确格式:
GRANT SELECT (id, email) ON mydb.t1 TO 'u2'@'localhost';
错误示例:
GRANT SELECT ON mydb.t1(id)
→ 报错
ERROR 1064 (42000)
错误示例:
GRANT SELECT ('name') ON mydb.t1
→ 单引号导致列名被当字符串字面量,权限不生效 注意大小写:列名区分大小写(取决于
lower_case_table_names
设置,但列名本身按定义时的大小写匹配) 列权限和表权限叠加时,以“最严格”为准 如果一个用户既被授予了整张表的
SELECT
权限,又被单独授予某几列的
SELECT
权限,MySQL 不会合并——它只认“最小交集”。比如:用户有
SELECT ON test.t1
(全表),又额外被收回
SELECT (ssn) ON test.t1
,那
ssn
列仍然不可查;反过来,如果只给了
SELECT (name)
,没给表级权限,那哪怕
SELECT *
里包含
name
,只要语句里出现其他列,整个查询就失败。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载
SELECT name FROM t1
✅(只查被授权列)
SELECT name, email FROM t1
❌(
email
未授权,整条语句拒绝)
SELECT * FROM t1
❌(即使其中一列被授权,
*
展开后含未授权列) 撤销列权限用
REVOKE SELECT (ssn) ON db.tbl FROM 'u'@'%';
,不是
DROP
DELETE
SHOW GRANTS 看不到列权限细节,得查系统表
SHOW GRANTS FOR 'u'@'%'
默认只显示表级权限,哪怕你确实授过列权限,输出里也不会出现括号列名——容易误以为没生效。真实授权信息存在
mysql.columns_priv
表里,需手动查:
SELECT User, Host, Db, Table_name, Column_name, Select_priv FROM mysql.columns_priv WHERE User = 'u1' AND Db = 'test' AND Table_name = 'users';
注意:
columns_priv
表权限是行级缓存的,修改后要执行
FLUSH PRIVILEGES;
才能立即生效(虽然多数情况下自动重载,但遇到权限不生效,先刷一下)。 容易被忽略的是:列权限不会出现在
INFORMATION_SCHEMA.ROLE_TABLE_GRANTS
中,也不受角色(ROLE)的间接继承影响——MySQL 目前不支持把列权限赋予 ROLE 再分配给用户。

相关文章