revoke 命令必须配合 on 和 from 使用,缺一不可
MySQL 的
REVOKE不是独立生效的命令,它必须明确指定「收回哪些权限」「在哪个对象上」「从哪个用户」。漏掉
ON或
FROM会直接报语法错误,比如:
ERROR 1064 (42000): You have an error in your SQL syntax。
基本结构是:
REVOKE priv_type ON db.table FROM 'user'@'host';
priv_type可以是
SELECT、
INSERT、
ALL PRIVILEGES等;多个权限用逗号分隔,如
SELECT, UPDATE
ON后的对象范围要和当初
GRANT时完全一致:库级写
db.*,表级写
db.table,全局写
*.*
FROM后的用户必须带引号,且主机部分(如
'localhost'或
'%')要和创建用户时一致,否则 MySQL 找不到匹配账户
回收 ALL PRIVILEGES 后,USAGE 权限仍保留
执行
REVOKE ALL PRIVILEGES ON *.* FROM 'u1'@'%';并不会让该用户彻底“失效”。MySQL 会自动保留一个隐式的
USAGE权限——它不赋予任何实际操作能力,但允许用户连接服务器(只要密码正确)。这意味着用户还能登录,只是执行任何 DML/DQL 都会报
ERROR 1142 (42000): SELECT command denied类错误。
若要彻底禁用账号,得额外执行:
DROP USER 'u1'@'%';或
ALTER USER 'u1'@'%' ACCOUNT LOCK;
回收权限后必须执行 FLUSH PRIVILEGES 吗?
不需要。MySQL 8.0+ 中,
REVOKE是即时生效的,权限变更直接写入系统表(如
mysql.role_edges、
mysql.db),服务端内存缓存会自动刷新。只有在极少数手动修改了系统表(比如用
UPDATE mysql.user)之后,才需要
FLUSH PRIVILEGES。
常见误操作:在
REVOKE后多加一句
FLUSH PRIVILEGES,虽然不报错,但纯属冗余,还可能掩盖权限未生效的真实原因(比如
ON范围写错了)。
跨库权限回收容易漏掉 db.* 级别授权
用户可能同时拥有多个层级的权限:全局(
*.*)、库级(
sales.*)、表级(
sales.orders)。只对某张表执行
REVOKE SELECT ON sales.orders FROM 'u1'@'%';,不影响其对整个
sales库的访问能力。
排查方法:
SHOW GRANTS FOR 'u1'@'%';,逐条检查输出结果。重点看是否有更宽泛的授权覆盖了你想收回的细粒度权限。
若需彻底清除某用户的库级权限,必须显式回收:
REVOKE SELECT, INSERT ON sales.* FROM 'u1'@'%';
权限继承关系是“取并集”,不是“取交集”——哪怕只有一处
GRANT SELECT ON *.*存在,用户就能查所有表。
