mysql不支持仅靠grant execute实现“可执行但不可看源码”,因无独立view definition权限;必须精确授予grant execute on procedure mydb.calc_score to 'app_user'@'%',并显式回收show routine和information_schema.routines的select权限。

不能只靠 GRANT EXECUTE 就实现“可执行但不可看源码”——MySQL 没有独立的 “VIEW DEFINITION” 权限,EXECUTE 和源码可见性完全解耦,必须组合控制。
GRANT EXECUTE ON PROCEDURE 语法必须精确到库和过程名
MySQL 不接受模糊授权。想让 app_user 只能调用 mydb.calc_score,就得写全:
GRANT EXECUTE ON PROCEDURE `mydb`.`calc_score` TO 'app_user'@'%';
常见错误包括:
-
GRANT EXECUTE ON calc_score TO ...:缺数据库名,报ERROR 1044 -
GRANT EXECUTE ON mydb.* TO ...:授的是整个库所有 routine,不是“特定过程” -
GRANT EXECUTE ON PROCEDURE mydb.*:语法非法,MySQL 不识别通配符在过程名位置 - MySQL 5.7 完全不支持
ON PROCEDURE语法,会直接报ERROR 1064;必须升级到 8.0.16+ 才可用
EXECUTE 权限 ≠ 查看源码权限,但默认配置常悄悄放开后者
用户能 SHOW CREATE PROCEDURE 或查 INFORMATION_SCHEMA.ROUTINES,靠的不是 EXECUTE,而是两个独立权限:
-
SHOW ROUTINE:控制SHOW CREATE PROCEDURE是否成功 -
SELECTonINFORMATION_SCHEMA.ROUTINES:直接读取ROUTINE_DEFINITION字段(即明文源码)
这两个权限默认不随 EXECUTE 自动授予,但很多初始化脚本或 GRANT ALL 会一并打开。所以即使你只给了 EXECUTE,用户仍可能看到源码——得主动关掉:
REVOKE SHOW ROUTINE ON *.* FROM 'app_user'@'%';<br>REVOKE SELECT ON INFORMATION_SCHEMA.ROUTINES FROM 'app_user'@'%';
DEFINER 和 SQL SECURITY 对执行成败影响远大于源码控制
过程默认是 SQL SECURITY DEFINER,执行时以 DEFINER 账号身份检查底层表权限。这意味着:
- 即使
app_user对mydb.users表零权限,只要DEFINER(如'dba'@'localhost')有SELECT,CALL就能成功 - 但如果过程里用了
SQL SECURITY INVOKER,则app_user必须自己有对应表权限,否则报EXECUTE command denied——这个错误提示极具误导性,实际缺的是表权限,不是EXECUTE -
DEFINER设置本身对源码是否可见毫无影响,别指望它防泄露
最容易被忽略的坑:权限对象匹配、主机名区分、版本兼容
权限失效往往不是语法错,而是细节没对齐:
- 授权的是
'app_user'@'10.20.%',但用户用mysql -u app_user -h 127.0.0.1连,实际匹配到的是'app_user'@'localhost',权限不生效 - 过程创建在
testdb,但你授的是GRANT EXECUTE ON PROCEDURE mydb.p1,对象根本不存在于该库 - MySQL 8.0+ 启用角色后,
EXECUTE若授给角色而非用户,需显式SET ROLE role_name;才生效 - 用
INSERT INTO mysql.procs_priv直接改权限表后,必须FLUSH PRIVILEGES;但常规GRANT语句在 5.7.6+ 默认自动刷新,手动执行反而可能掩盖主机名解析问题











