<p>REVOKE ALL PRIVILEGES ON db_name.* 没清干净,因其仅撤销显式授予的数据库级权限,不处理 GRANT OPTION、USAGE 连接权、角色继承、列级或存储过程权限,且已建立连接仍保留旧权限快照。</p>

REVOKE ALL PRIVILEGES ON db_name.* 为什么没清干净?
因为这条命令只撤销显式授予该库范围的权限,不碰 GRANT OPTION、USAGE 连接权、角色继承权限,也不清理列级或存储过程权限。用户仍可能连得上、查 information_schema、甚至给他人授权。
必须分层执行:
-
REVOKE ALL PRIVILEGES, GRANT OPTION ON `db_name`.* FROM 'user'@'host';(反引号防关键字冲突) - 查列级权限:
SELECT * FROM mysql.columns_priv WHERE User='user' AND Host='host' AND Db='db_name';,有结果就逐条REVOKE UPDATE(col_a) ON db_name.tbl FROM 'user'@'host'; - 查过程/函数权限:
SELECT * FROM mysql.procs_priv WHERE User='user' AND Host='host' AND Db='db_name';,存在则补REVOKE EXECUTE ON PROCEDURE db_name.p1 FROM 'user'@'host';
撤销后 SELECT 还能执行,是命令没生效吗?
不是。MySQL 权限检查基于会话快照,REVOKE 只更新服务端权限表,已建立的连接(包括连接池里的长连接)不会自动丢弃旧权限。
验证是否真生效,必须:
- 新开终端执行
mysql -u user -p -e "SELECT * FROM db_name.t1 LIMIT 1;" - 或在当前会话里先
SET ROLE NONE;(如果启用了角色) - 生产环境建议配合
ALTER USER 'user'@'host' ACCOUNT LOCK;阻断新连接,再等应用侧滚动重启
为什么 SHOW GRANTS 显示还有权限,但 REVOKE 却报 “no such grant”?
常见于权限来源不唯一:用户可能通过角色、代理账号、或多个 GRANT 语句叠加获得同一权限。比如 SHOW GRANTS FOR 'u'@'%' 显示 SELECT ON db1.*,但当初不是直接授的,而是来自角色 reader_role。
这时要查清来源:
-
SHOW GRANTS FOR 'u'@'%' USING 'reader_role';看角色内权限 -
SELECT * FROM mysql.role_edges WHERE TO_USER='u' AND TO_HOST='%';确认绑定关系 - 若确认需移除,执行
REVOKE 'reader_role' FROM 'u'@'%';
用 DROP USER 能替代 REVOKE 吗?
不能混用。DROP USER 是彻底删账号,会清空 mysql.user、mysql.db、mysql.tables_priv 所有记录,但也会让账号消失——而你只是想保留账号、只清权限。
误用 DROP USER 的后果:
- 应用配置里还写着这个用户名,重启后直接连不上
- 如果该用户被其他账号设为 PROXY,
mysql.proxies_priv里残留会导致静默失败 - MySQL 8.0+ 角色绑定不会自动解绑,删用户后角色可能成孤儿
真正麻烦的从来不是语法写错,而是没意识到权限可能来自多个路径,且已有连接不会自动同步变更。


















