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

根本原因不是“权限没给”,而是 EXECUTE 权限没给到存储过程这个具体对象上——哪怕用户对整个库有 ALL PRIVILEGES,只要没显式执行 GRANT EXECUTE ON PROCEDURE,调用 CALL proc_name() 就会报 ERROR 1370 (42000)。
EXECUTE 权限必须显式授予存储过程对象
MySQL 不把存储过程当作普通表或库来继承权限。以下写法全都不生效:
-
GRANT EXECUTE ON db_name.* TO 'u'@'h'—— 这是授给“该库下所有过程”,但语法里缺PROCEDURE关键字,MySQL 会静默当成数据库权限处理 -
GRANT SELECT, INSERT ON db_name.* TO 'u'@'h'—— 对表有读写权 ≠ 能调过程,权限不传递 -
GRANT CREATE ROUTINE ON db_name.* TO 'u'@'h'—— 这只是允许创建过程,和执行无关
唯一有效的写法是:
GRANT EXECUTE ON PROCEDURE db_name.proc_name TO 'u'@'h';
注意:PROCEDURE 关键字不可省略,db_name.proc_name 必须写全名,不能模糊匹配。
SHOW GRANTS 看不到 EXECUTE 条目就是没授权成功
执行完 GRANT 后别急着重试,先验证:
SHOW GRANTS FOR 'u'@'h';
输出中必须出现类似这样的行:
GRANT EXECUTE ON PROCEDURE `db_name`.`proc_name` TO 'u'@'h'
如果只看到 USAGE、SELECT 或 EXECUTE ON db_name.*,说明授权失败或授错对象。另外注意:'u'@'localhost' 和 'u'@'%' 是两个完全不同的用户,权限不互通。
EXECUTE 权限给了还报错?查 SQL SECURITY 定义
即使 GRANT EXECUTE 成功,调用仍失败,大概率是存储过程定义时用了 SQL SECURITY DEFINER(MySQL 默认),导致权限校验不看调用者,而看创建者(DEFINER)是否还存在、是否有底层表权限:
- 用
SHOW CREATE PROCEDURE proc_name查定义,确认是否含SQL SECURITY DEFINER - 如果 DEFINER 用户已被删,或其对某张表的
SELECT权限被回收,则调用者哪怕有EXECUTE也会失败 - 临时修复:重建过程,加上
SQL SECURITY INVOKER;长期建议避免依赖特定 DEFINER
跨库操作时更明显:过程里有 SELECT * FROM other_db.t1,EXECUTE 权限只解决“能不能调”,不解决“过程内部能不能读 other_db.t1”——此时调用者还得额外有 other_db.t1 的 SELECT 权限。
FLUSH PRIVILEGES 不是必需的,但 host 必须完全一致
GRANT 语句本身会自动刷新权限缓存,不需要手动 FLUSH PRIVILEGES。真正容易被忽略的是 host 字符串必须一字不差:
- 连接时用的是
mysql -u u -h 192.168.1.100 -p,授权就得是'u'@'192.168.1.100',不是'u'@'%' - 如果应用通过代理或跳板机连接,实际
host可能是代理 IP,而非客户端真实 IP - 用
SELECT USER(), CURRENT_USER();能准确看到 MySQL 认为的当前用户是谁
最麻烦的情况是 DEFINER 用户被删后未重建,又没改 SQL SECURITY,这时候光看 SHOW GRANTS 会误以为权限没问题——得进过程定义里一层层扒。











