MySQL不提供独立的EXPLAIN权限,其执行依赖SELECT(必需)、PROCESS(复杂查询必需)及INFORMATION_SCHEMA.SELECT(影响字段精度)三类权限组合。

MySQL 没有独立的 EXPLAIN 权限
直接回答:你无法单独授予 EXPLAIN 权限,MySQL 官方不提供这个权限粒度。所谓“给账号授权 EXPLAIN”,本质是让它能跑通 EXPLAIN 所需的全部前置条件——而这些条件恰好也允许它执行 SELECT,甚至意外触发函数副作用。
常见错误现象:EXPLAIN SELECT * FROM (SELECT cleanup()) t 会真实执行 cleanup(),删掉数据,但用户没写任何 DELETE 语句。
真正起作用的是三类权限组合:
-
SELECT:必须有,否则EXPLAIN直接报错ERROR 1142 (42000): SELECT command denied -
PROCESS:涉及子查询、派生表、临时表时必需;缺它会报ERROR 1227 (42501): Access denied; you need (at least one of) the PROCESS privilege(s) - 对
INFORMATION_SCHEMA的SELECT:影响key_len、ref等字段是否显示准确;禁用后部分字段为NULL,但EXPLAIN仍能运行
只允许 SELECT + EXPLAIN,禁止 DELETE/UPDATE/INSERT 的实操配置
核心思路:授最小集权限,不碰 ALL PRIVILEGES,显式列出允许项,并确保不包含危险权限。
正确授权命令示例(以数据库 app_db 为例):
GRANT SELECT ON app_db.* TO 'dev_user'@'10.0.2.%'; GRANT PROCESS ON *.* TO 'dev_user'@'10.0.2.%'; FLUSH PRIVILEGES;
关键点说明:
- 不授
DELETE、UPDATE、INSERT、DROP、CREATE等任何 DML 或 DDL 权限 -
PROCESS是全局权限(ON *.*),不能按库限制;但它本身不等于“能看所有线程”,只是让EXPLAIN走得通 - 不要授
SHOW DATABASES,否则用户能列出所有库名;如需隐藏,可配合skip-show-database配置或收回该权限 - 如果开发真不需要看执行计划细节(比如只查慢日志里已有的 SQL),可省略
PROCESS,仅留SELECT——此时简单查询的EXPLAIN仍可用,复杂嵌套则失败
为什么 REVOKE DELETE 不够?还得防 INFORMATION_SCHEMA 泄露
只撤 DELETE 权限,不代表业务逻辑就安全了。EXPLAIN 输出本身就能反推表结构、索引选择、WHERE 条件强度,而 INFORMATION_SCHEMA.ROUTINES 和 INFORMATION_SCHEMA.VIEWS 更是明文暴露存储过程和视图定义。
建议同步执行:
REVOKE SELECT ON INFORMATION_SCHEMA.* FROM 'dev_user'@'10.0.2.%'; FLUSH PRIVILEGES;
注意:
- MySQL 8.0+ 支持对
INFORMATION_SCHEMA显式回收权限;5.7 及更早版本该操作无效,只能靠网络层隔离或应用层过滤 - 收回后,
SHOW CREATE VIEW、SHOW CREATE PROCEDURE会报权限错误,但EXPLAIN本身不受影响 - 别忘了检查该用户是否已有
EXECUTE权限——若有,且函数含副作用,EXPLAIN仍可能误删数据
容易被忽略的副作用:EXPLAIN 真的会改数据
这不是 bug,是 MySQL 的设计行为:为了准确估算成本,它必须真实求值表达式,包括调用存储函数、触发器。PostgreSQL 的 EXPLAIN 默认不执行函数,更安全;MySQL 没这层隔离。
所以最稳妥的做法不是“怎么让 EXPLAIN 安全”,而是:
- 开发环境用专用账号,该账号无
EXECUTE权限,且函数体不含副作用 - 生产环境禁止开发账号连生产库;所有
EXPLAIN必须在预发或脱敏库执行 - 如果业务函数确实要清理数据(如
cleanup_expired_sessions()),把它从查询中剥离,改用应用层定时任务调用
权限配置只是防线之一,真正堵住泄露口,得从函数设计、环境隔离、访问路径三处同时下手。


















