MySQL 8.0.16+才支持GRANT EXECUTE ON PROCEDURE,需先授USAGE权限、过程名带库名且DEFINER存在,否则CALL静默失败或报ERROR 1370;5.7不识别该语法,直接报ERROR 1064。

必须显式授予 GRANT EXECUTE ON PROCEDURE,但仅靠它无法实现“可执行、不可看源码”,且极易因版本、DEFINER、host 匹配等问题静默失效。
MySQL 5.7 和 8.0+ 的 EXECUTE 授权语法根本不同
MySQL 5.7 完全不识别 GRANT EXECUTE ON PROCEDURE,执行直接报 ERROR 1064 (42000);只有 8.0.16+ 才支持该语法,且有硬性前提:
- 必须先执行
GRANT USAGE ON `db_name`.* TO 'user'@'%'(缺了这步,GRANT EXECUTE ON PROCEDURE看似成功,实际调用仍报错) - 过程名必须带库名:
GRANT EXECUTE ON PROCEDURE mydb.p_calc✅,GRANT EXECUTE ON PROCEDURE p_calc❌ -
GRANT EXECUTE ON PROCEDURE mydb.*是非法语法,MySQL 不接受通配符在对象名位置 - 兼容性兜底方案:对整个库授
GRANT EXECUTE ON mydb.* TO 'user'@'%',5.7 和 8.0 都支持
CALL 报 ERROR 1370 几乎从不因为没授 EXECUTE
这个错误是 MySQL 权限校验失败的“万能错误码”,真正卡点往往在运行时上下文:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 检查
SHOW CREATE PROCEDURE mydb.p_calc中的DEFINER字段:若指向已删除或锁定的账号(如'dba'@'localhost'),过程会 fallback 到调用者权限,此时哪怕 EXECUTE 已授,也会因调用者缺底层表权限而失败 - 连接 host 必须严格匹配:授权是
'appuser'@'10.20.%',但应用连的是'appuser'@'localhost'—— MySQL 视为两个独立用户,权限不共享 - 过程内用了跨库表(如
otherdb.users),但DEFINER或调用者没有otherdb的SELECT权限 - 过程含动态 SQL(
PREPARE/EXECUTE),MySQL 按调用者权限检查语句中涉及的表,此时SQL SECURITY INVOKER才生效
想“可执行但不可看源码”,必须组合回收权限
MySQL 没有 VIEW DEFINITION 这类独立权限,EXECUTE 和源码可见性完全解耦:
-
SHOW CREATE PROCEDURE成败取决于SHOW ROUTINE权限,需显式回收:REVOKE SHOW ROUTINE ON *.* FROM 'user'@'%' - 查
INFORMATION_SCHEMA.ROUTINES表看明文源码,靠的是SELECT权限,需回收:REVOKE SELECT ON INFORMATION_SCHEMA.ROUTINES FROM 'user'@'%' - 只授
EXECUTE不等于安全 —— 很多初始化脚本或GRANT ALL会一并打开上述权限,必须主动关掉 -
SQL SECURITY DEFINER对源码是否可见毫无影响,别指望它防泄露
最容易被忽略的权限验证盲区
别只信自己执行过 GRANT 语句,真实生效与否得靠交叉验证:
- 运行
SHOW GRANTS FOR 'user'@'%',输出里必须出现形如GRANT EXECUTE ON PROCEDURE `mydb`.`p_calc`的行才算真正授到 - 确认用户连接的实际 host:
SELECT USER(), CURRENT_USER();—— 前者是客户端声明的用户,后者才是 MySQL 实际匹配的账号,两者常不一致 - 过程定义在
mydb,但调用时写成CALL p_calc()(未带库名),MySQL 会按当前默认库查找,若当前库不是mydb就直接报错,和权限无关 - 权限变更后未执行
FLUSH PRIVILEGES(尤其在手动修改系统表后),会导致新授权延迟生效










