用户有execute权限却调用失败,大概率因mysql默认sql security definer导致权限校验绕过调用者而检查创建者;需确认definer用户是否存在、权限是否完整,并确保授权host与实际连接host完全一致。

用户有 EXECUTE 权限却调用失败,大概率不是权限没给,而是权限校验绕过了调用者——MySQL 默认用 SQL SECURITY DEFINER,实际检查的是存储过程创建者的权限,不是你。
为什么 SHOW GRANTS 显示有 EXECUTE 还报错?
因为 GRANT EXECUTE ON PROCEDURE 只解决“能不能调”,不解决“调了之后能不能跑通”。错误常发生在过程内部执行某条 SQL 时,比如 SELECT FROM other_db.t1 或 INSERT INTO log_table。此时权限检查对象变成定义者(DEFINER),而非当前用户。
- 用
SHOW CREATE PROCEDURE proc_name查定义,重点看SQL SECURITY DEFINER(默认)还是SQL SECURITY INVOKER - 如果含
DEFINER='definer_user'@'host',就去查那个definer_user是否还存在、是否仍有访问相关表的权限 -
DEFINER用户被删、密码过期、或被 revoke 了某张表的SELECT权,都会导致调用失败
如何确认是 DEFINER 权限问题?
最直接的办法是临时切换成 INVOKER 模式测试:
- 导出原过程定义:
SHOW CREATE PROCEDURE proc_name - 把输出里的
SQL SECURITY DEFINER改成SQL SECURITY INVOKER,再DROP PROCEDURE+CREATE PROCEDURE重建 - 用同一用户重试
CALL proc_name();如果成功,基本锁定是 DEFINER 权限失效
注意:重建后要重新授 EXECUTE 权限,因为 DROP 会清掉 mysql.procs_priv 中对应记录。
调用时 host 不匹配也会静默失败
MySQL 把 'user'@'localhost' 和 'user'@'%' 当作两个完全独立的账号,权限不共享。哪怕你用 GRANT EXECUTE ON PROCEDURE db.p TO 'u'@'%',但连接时实际走的是 socket(即 localhost),那这条授权就完全不生效。
- 查当前连接用的 host:
SELECT USER(), CURRENT_USER();—— 前者是客户端声明的用户,后者才是 MySQL 实际认证的账号 - 如果
CURRENT_USER()返回'u'@'localhost',但授权只给了'u'@'%',就得补一条:GRANT EXECUTE ON PROCEDURE db.p TO 'u'@'localhost' - 不要依赖
'u'@'%'覆盖所有情况,尤其本地开发环境常走localhost
权限给了但没刷新?
极少见,但真实存在:某些 MySQL 版本(尤其是 5.7 早期小版本)在 GRANT 后不自动刷新权限缓存,导致新授权延迟生效。
- 执行
FLUSH PRIVILEGES;强制重载权限表 - 更稳妥的做法是:授完权后,立刻用目标用户连接并执行
SHOW GRANTS;验证是否已加载 - MySQL 8.0+ 大部分情况下自动刷新,但跨主机部署或使用 ProxySQL 时仍建议手动刷一次
真正难排查的点,往往不在 EXECUTE 授权本身,而在于 DEFINER 的存在性、权限完整性,以及 host 字符串是否和实际连接完全一致——这三个地方差一个字符,错误现象都一样:明明有权限,就是不能执行。











