MySQL列级权限仅支持SELECT/INSERT/UPDATE/REFERENCES,DELETE等行级操作不支持列粒度;授权时列名错误不报错但查询会失败;UPDATE需授权WHERE中所有列;列权限与表权限共存时后者覆盖前者。
列级权限只支持 SELECT/INSERT/UPDATE,DELETE 不行
MySQL 的列级权限不是“所有操作都能按列控制”,它只对 SELECT、INSERT、UPDATE、REFERENCES 四种操作生效。像 DELETE、TRUNCATE、ALTER 这类天然作用于整行的操作,压根不支持列粒度——你写 GRANT DELETE (id) ON db.tbl TO 'u'@'h',MySQL 会默默忽略括号里的列名,降级成表级 DELETE 权限(如果用户本来就有),或者直接报语法错(取决于版本)。所以别白费劲去试列级 DELETE,真要限制删数据,得靠视图、存储过程封装,或从应用层拦截。
授权语句写错列名,不会报错,但查询直接崩
这是最常踩的坑:执行 GRANT SELECT (name, email) ON test.users TO 'reader'@'%',如果 test.users 表里根本没有 email 这一列,MySQL 不会拒绝授权,也不会警告,语句照样返回 Query OK。但之后用户一查 SELECT email FROM test.users,得到的不是权限错误,而是赤裸裸的 Unknown column 'email' in 'field list'。你以为是权限没给对,其实只是列名拼错了。
- 授权前先确认列存在:
DESCRIBE test.users或SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='users' - 注意大小写:列名是否区分大小写,取决于系统变量
lower_case_table_names的设置,别凭感觉猜 - 别靠报错反推权限问题——先查结构,再查权限
UPDATE 列权限比你想的更严格
UPDATE 列权限不是“只允许改这些字段”那么简单。它要求整个语句涉及的所有列(包括 WHERE 子句里用到的列)都必须在授权范围内。比如你只授了 GRANT UPDATE (status) ON app.orders TO 'worker'@'10.0.1.%',那用户连 UPDATE app.orders SET status = 'done' WHERE id = 123 都执行不了,因为 WHERE id = 123 引用了未授权的 id 列,直接报 ERROR 1142 (42000): UPDATE command denied to user。