mysql中grant execute on procedure必须指定完整库名和过程名,如grant execute on procedure mydb.get_user_info to 'dev'@'%';不支持省略库名或使用通配符;需单独回收show routine和information_schema.routines权限以防源码泄露。

GRANT EXECUTE ON PROCEDURE 语法必须写全库名和过程名
MySQL 不接受 GRANT EXECUTE ON calc_score TO 'dev'@'%' 这类缺库名的写法,会直接报 ERROR 1044 (42000): Access denied。也不能用通配符代替过程名,GRANT EXECUTE ON PROCEDURE mydb.* 是非法语法,MySQL 会报 ERROR 1064。
正确写法必须精确到数据库和过程两级:
GRANT EXECUTE ON PROCEDURE `mydb`.`get_user_info` TO 'dev'@'%';- 若要授权多个过程,需逐条执行,不支持批量
- 库名和过程名含特殊字符时,必须用反引号包裹
必须显式回收 SHOW ROUTINE 和 INFORMATION_SCHEMA 权限
只给 EXECUTE 不等于“能执行但看不到源码”。开发人员仍可能通过 SHOW CREATE PROCEDURE mydb.get_user_info 或查 INFORMATION_SCHEMA.ROUTINES 看到明文定义——这两个操作依赖的是独立权限:
-
SHOW ROUTINE:控制SHOW CREATE PROCEDURE是否成功 -
SELECT ON INFORMATION_SCHEMA.ROUTINES:直接读取ROUTINE_DEFINITION字段
这两个权限默认不会随 EXECUTE 自动授予,但很多初始化脚本或 GRANT ALL 会一并打开。所以务必补上:
REVOKE SHOW ROUTINE ON *.* FROM 'dev'@'%';REVOKE SELECT ON INFORMATION_SCHEMA.ROUTINES FROM 'dev'@'%';
SQL SECURITY DEFINER 是执行成败的关键,不是源码可见性的开关
存储过程默认是 SQL SECURITY DEFINER,这意味着它运行时检查的是创建者(如 'dba'@'localhost')的表权限,而不是调用者权限。这对开发人员很关键:
- 即使
'dev'@'%'对mydb.users表没有任何SELECT权限,只要过程的DEFINER有,CALL就能成功 - 但如果过程里显式写了
SQL SECURITY INVOKER,那'dev'@'%'就必须自己拥有对应表权限,否则报EXECUTE command denied——这个错误提示极具误导性,实际缺的是底层表权限 -
DEFINER设置对源码是否可见完全没影响,别指望靠它防泄露
MySQL 8.0+ 的权限对象匹配比你想的更严格
权限失效最常见的原因不是语法错,而是细节没对齐:
- 用户连接时用的是
'dev'@'10.20.5.100',但你授的是'dev'@'%'——没问题;可如果授的是'dev'@'10.20.%',而客户端 IP 是10.20.50.100,就匹配不上 -
'dev'@'localhost'和'dev'@'%'是两个完全独立账户,权限不互通 - 确认过程真实归属库:
SELECT db, name FROM mysql.proc WHERE name = 'get_user_info'(注意:MySQL 8.0 已弃用该表,建议改用SELECT routine_schema, routine_name FROM information_schema.routines WHERE routine_name = 'get_user_info') - 检查当前生效权限:
SHOW GRANTS FOR 'dev'@'%';
最容易被忽略的点是:权限对象中的主机名、数据库名、过程名三者必须和实际调用时完全一致,一个空格、大小写、反引号都可能导致失败。











