根本原因是execute权限未显式授予存储过程对象本身,必须用grant execute on procedure db_name.proc_name to 'user'@'host';缺procedure关键字、用库级授权或权限继承均无效。

用户执行 CALL proc_name() 报错 ERROR 1370 (42000): execute command denied to user,根本原因不是“没权限”,而是 EXECUTE 权限没授到存储过程对象本身——只给表权限、库权限甚至 CREATE ROUTINE 都不顶用。
GRANT EXECUTE ON PROCEDURE 是唯一有效写法
MySQL 不支持模糊匹配或继承式授权。必须显式指定存储过程全名,且语法中 PROCEDURE 关键字不可省略:
-
GRANT EXECUTE ON PROCEDURE db_name.proc_name TO 'user'@'host'✅ 正确,粒度最细、最安全 -
GRANT EXECUTE ON db_name.* TO 'user'@'host'⚠️ 可行但危险:授予该库下所有现有及未来新建的存储过程(含他人创建) -
GRANT EXECUTE ON db_name.proc_name TO 'user'@'host'❌ 缺少PROCEDURE关键字,语句会静默失败或授错对象(如当成数据库权限) -
GRANT SELECT ON db_name.* TO ...❌ 对表有读写权 ≠ 能调过程;权限不传递
为什么 SHOW GRANTS 看不到 EXECUTE 就基本能定位问题
直接查 SHOW GRANTS FOR 'user'@'host' 是最快验证方式。注意两个关键点:
- 输出里必须出现类似
GRANT EXECUTE ON PROCEDURE `db_name`.`proc_name` TO ...的条目;只有USAGE或表级权限都不算数 - 连接时用的 host 必须和授权语句完全一致:
'user'@'localhost'和'user'@'%'是两个不同用户,权限不互通 - 如果用户通过角色(role)获得权限,需确认角色已激活:
SELECT CURRENT_ROLE();
EXECUTE 权限给了还报错?重点查 SQL SECURITY
即使 GRANT EXECUTE 成功,调用仍失败,大概率是存储过程定义时用了 SQL SECURITY DEFINER(MySQL 默认),导致权限校验绕过调用者,转而检查创建者(DEFINER)是否还存在、是否有底层对象权限:
- 用
SHOW CREATE PROCEDURE proc_name查当前定义,看是否含SQL SECURITY DEFINER - 若 DEFINDER 用户已被删,或其对某张表的
SELECT权限被回收,则调用者哪怕有EXECUTE也会失败 - 临时修复:重建过程,加上
SQL SECURITY INVOKER;长期建议按最小权限原则,避免依赖特定 DEFINER
跨库/跨 schema 查询时,EXECUTE 权限只是起点
GRANT EXECUTE 只解决“能不能调这个过程”,不解决“过程内部能不能读写其他库的表”。例如过程里有 SELECT * FROM other_db.t1:
- 如果过程是
SQL SECURITY INVOKER,调用者必须额外拥有other_db.t1的SELECT权限 - 如果是
SQL SECURITY DEFINER,则需要 DEFINER 用户拥有该权限——这时得去补 DEFINER 的权限,不是调用者的 - Oracle/SQL Server 同理:跨 schema 表访问,
EXECUTE权限之外,必须单独授表级权限给对应主体(调用者或 DEFINER)
真正容易被忽略的是:权限生效不等于行为可控。EXECUTE 是门禁卡,但门后每间屋子的钥匙(表权限)、谁来开门(SQL SECURITY)、甚至门锁是否被重置(DEFINER 是否还存在),都得一一分清。否则赋完权还是报错,问题就藏在这些链路细节里。











