列级权限撤销必须显式列出所有原始授权列名,顺序无关但集合必须完全一致,否则无效;SHOW GRANTS 不显示列级权限,需查 mysql.columns_priv 表确认;撤销仅对新连接生效,旧连接仍保留权限。

列级权限撤销必须显式列出所有列名
MySQL 不支持模糊撤回或部分列撤回。如果你当初授权的是 UPDATE(col_a, col_b),现在只想撤 col_b,不能写 REVOKE UPDATE(col_b) 就完事——它必须和原始授权的列集合完全一致,否则命令执行成功但实际无效。
-
REVOKE UPDATE(col_b, col_a) ON db.tbl FROM 'u'@'h'合法(顺序无关) -
REVOKE UPDATE(col_b) ON db.tbl FROM 'u'@'h'无效(少列) -
REVOKE UPDATE(col_b, col_c) ON db.tbl FROM 'u'@'h'报错(多列) - 列名含空格或特殊字符时,必须用反引号包裹:
UPDATE(`col with space`)
SHOW GRANTS 看不到列级权限?查系统表确认
SHOW GRANTS FOR 'u'@'h' 默认不显示列级权限,容易误判“没授过”或“已撤掉”。真实权限藏在 mysql.columns_priv 表里。
- 先确认是否存在:
SELECT * FROM mysql.columns_priv WHERE User='u' AND Host='h' AND Db='db' AND Table_name='tbl'; - 返回非空结果,说明有列级权限;字段
Column_priv值是逗号分隔的权限列表,如Select,Update - 如果该表里有记录但
REVOKE没生效,大概率是列名没对齐,或者用户主机名不匹配
撤销后旧连接仍能操作,重连才生效
列级权限变更只对新连接生效。已建立的连接(尤其是应用连接池里的长连接)仍持有授权快照,SELECT col_b FROM tbl 或 UPDATE tbl SET col_b=1 还能成功执行,直到断开重连。
- 验证是否真撤掉:新开一个
mysql -u u -p -h h连接,再跑测试语句 - 生产环境务必配合应用重启或连接池刷新(如 HikariCP 的
evictAllConnections()) - 别依赖
FLUSH PRIVILEGES—— MySQL 8.0+ 下它对REVOKE无影响,纯属冗余
别漏掉 GRANT OPTION 和角色继承
列级权限可能通过角色间接授予,也可能带 WITH GRANT OPTION。只撤直接权限,不处理这两项,等于留了后门。
- 查角色继承:
SELECT * FROM mysql.role_edges WHERE TO_HOST='h' AND TO_USER='u'; - 若存在,需额外执行:
REVOKE role_name FROM 'u'@'h'; - 检查是否曾授过转授权:
SELECT Grant_priv FROM mysql.tables_priv WHERE User='u' AND Host='h' AND Db='db' AND Table_name='tbl'; - 如有,必须显式撤:
REVOKE GRANT OPTION ON db.tbl(col_a, col_b) FROM 'u'@'h';
列级权限撤销最易踩的坑不是语法写错,而是以为“执行了就生效”,结果权限还在旧连接里跑着;更隐蔽的是权限来自角色或系统表残留,SHOW GRANTS 完全不露痕迹。


















