execute权限仅控制调用存储过程或函数,不涉及创建、修改或查看定义;需配合definer/invoker权限校验,且必须按数据库.对象粒度授予,无法跨库通配。

MySQL中EXECUTE权限到底控制什么
EXECUTE权限只控制用户能否调用(CALL)存储过程或函数,不涉及创建、修改或查看定义。即使用户没有SELECT权限,只要拥有EXECUTE权限,也能成功执行过程——前提是过程内部的SQL语句能通过其定义者(DEFINER)或调用者(INVOKER)权限校验。
常见误解是:给了EXECUTE就能看过程体。其实不能。SHOW CREATE PROCEDURE 和 SELECT 系统表(如 mysql.proc)需要额外权限,比如 SELECT 或 PROCEDURE 权限(MySQL 8.0+ 已废弃该表,改用 information_schema.routines,仍需对应查询权限)。
授予EXECUTE权限的正确语法与范围
MySQL的EXECUTE权限必须按「数据库.对象」粒度授予,不能跨库通配,也不能只授给「所有过程」而不指定库名。权限作用域由ON子句严格限定:
-
GRANT EXECUTE ON PROCEDURE mydb.my_proc TO 'user1'@'localhost';—— 最精确,仅授权单个过程 -
GRANT EXECUTE ON mydb.* TO 'user1'@'localhost';—— 授权整个库下所有过程和函数(包括未来新建的) -
GRANT EXECUTE ON *.* TO 'user1'@'localhost';—— 全局级,极不推荐,风险高
注意:mydb.* 中的 * 是通配符,不代表“任意过程名”,而是指该库内所有可执行对象(PROCEDURE/FUNCTION),不包含表或视图。
为什么GRANT EXECUTE后还是报错ERROR 1370 (42000)
典型错误信息:execute command denied to user 'user1'@'localhost' for routine 'mydb.my_proc'。这通常不是权限没给,而是以下任一原因:
- 用户连接时用的是不同主机名(比如授权的是
'user1'@'127.0.0.1',但实际连的是'user1'@'localhost'),MySQL视作两个账户 - 存储过程使用了
SQL SECURITY DEFINER(默认),而DEFINER指定的账号(如'admin'@'localhost')本身已不存在,或该账号无权执行过程内涉及的表操作 - MySQL 8.0+ 启用了角色(roles),但EXECUTE权限被赋予角色而非直接授给用户,且用户未激活该角色(需
SET ROLE role_name;) - 执行前未刷新权限缓存(尤其在命令行快速测试时),应运行
FLUSH PRIVILEGES;(仅当用INSERT直改系统表才必需;常规GRANT后一般自动生效)
如何验证EXECUTE权限是否真正生效
别只信GRANT语句跑过,要实测+查元数据:
- 用目标用户登录后执行:
CALL mydb.my_proc();—— 直接验证是否真能跑通 - 检查权限分配记录:
SELECT * FROM mysql.procs_priv WHERE User='user1' AND Db='mydb' AND Routine_name='my_proc';(MySQL 5.7及以前) - MySQL 8.0+ 应查:
SELECT * FROM information_schema.role_table_grants WHERE grantee="'user1'@'localhost'" AND privilege_type='EXECUTE';(若用角色)或结合information_schema.schema_privileges - 注意:
SHOW GRANTS FOR 'user1'@'localhost';只显示显式授予的权限,不反映通过角色继承的EXECUTE权限
最容易被忽略的是DEFINER账户状态和SQL SECURITY模式——哪怕EXECUTE权限100%正确,DEFINER失效也会导致CALL失败,且错误提示看起来像权限问题。











