REVOKE UPDATE必须严格匹配原授权的数据库名、表名和用户主机对,列级权限需显式指定列名,撤销后需重连验证生效,且须排查角色、高阶权限等间接路径。

REVOKE UPDATE必须写全ON子句和FROM子句
直接执行 REVOKE UPDATE ON db.tbl FROM 'u'@'h' 是唯一正确路径,不能省略数据库名、表名或用户主机对。MySQL 不会自动补全或推导作用域——REVOKE UPDATE ON db.* 会撤掉整库所有表的 UPDATE,REVOKE UPDATE ON *.* 则波及全局,错一个字符就可能误伤。
- 原授权是
GRANT UPDATE ON sales.orders TO 'analyst'@'10.0.2.%',撤销就必须严格匹配:不能写成'analyst'@'%',也不能漏掉.orders - 若用户有多个 host 记录(如
'u'@'localhost'和'u'@'192.168.1.%'),要分别执行两条REVOKE,否则只撤了一半 - 权限类型大小写敏感:
revoke update报错,必须大写UPDATE
列级UPDATE权限不能靠表级REVOKE覆盖
如果用户当初被授予的是列级 UPDATE(比如 GRANT UPDATE(col_a, col_b) ON db.tbl TO 'u'@'h'),那么执行 REVOKE UPDATE ON db.tbl FROM 'u'@'h' 完全无效——它只影响表级权限,对 mysql.columns_priv 里的记录毫无作用。
- 必须显式写出列名:
REVOKE UPDATE(col_a) ON db.tbl FROM 'u'@'h' - 反引号包裹的列名(如
`col with space`)撤销时也得带反引号,否则语法错误 - 先查系统表确认是否存在:
SELECT Column_name, Update_priv FROM mysql.columns_priv WHERE User='u' AND Host='h' AND Db='db' AND Table_name='tbl'
撤销后旧连接仍能UPDATE,必须重连验证
REVOKE 修改的是权限元数据,不中断当前会话。应用里用连接池维持的长连接,哪怕刚执行完 REVOKE,依然可以对 db.tbl 执行 UPDATE,直到连接断开重建。
- 验证是否真生效,必须开新连接测试:
mysql -u u -h host -D db -e "UPDATE tbl SET c=1 WHERE id=1" - 若需立即阻断,只能
KILL对应线程,或重启应用让连接池刷新 -
FLUSH PRIVILEGES在标准REVOKE后非必需,但加了不报错;它只在你手动UPDATE mysql.tables_priv等操作后才真正起效
别忘了排查其他权限路径
表级 UPDATE 被撤了,不代表用户彻底失去写能力。还可能通过更高层或间接方式绕过限制:
- 用户是否有
UPDATE ON db.*?那db.tbl自然可写,列级或表级撤销都压不住 - 是否通过角色获得权限?
SHOW GRANTS FOR 'u'@'h'若显示AS 'role_dev',得先REVOKE 'role_dev' FROM 'u'@'h' - 是否拥有
ALL PRIVILEGES?它包含UPDATE,但不会连带撤掉GRANT OPTION,后者得单独处理
REVOKE,而是搞清权限从哪来、在哪生效、当前连接还拿着什么快照——这些不查 mysql.columns_priv、不重连跑真实 UPDATE、不逐层排查角色与高阶权限,就容易留空子。


















