grant execute权限授予调用者而非存储过程本身,即只有被显式授权的用户才能执行指定过程;需精确到过程或数据库级授权,不支持全局*.*,且5.7+无需flush privileges。

MySQL中GRANT EXECUTE到底给谁?
不是给存储过程本身,而是给「调用者」——也就是说,只有被显式授予EXECUTE权限的用户,才能运行某个数据库下的存储过程。没授这个权,哪怕你是root(非当前连接用户身份),或者有SELECT/UPDATE等其他权限,照样报错:ERROR 1370 (42000): execute command denied to user。
实操建议:
-
GRANT EXECUTE ON PROCEDURE db_name.proc_name TO 'user'@'host';—— 精确到单个过程,最安全 -
GRANT EXECUTE ON db_name.* TO 'user'@'host';—— 给整个库下所有过程(含未来新建的),但注意:这不包含函数、视图或表 - 不能写成
GRANT EXECUTE ON *.*来全局授权过程——MySQL不支持这种语法,会报错 - 授权后必须执行
FLUSH PRIVILEGES;吗?不需要。MySQL 5.7+ 中GRANT语句会自动刷新权限缓存
为什么DEFINER用户权限不影响调用,却影响创建?
存储过程默认以DEFINER身份执行内部SQL(比如INSERT INTO logs),但调用权限和DEFINER无关——只看调用者有没有EXECUTE权。真正卡住你的是「创建过程」那一步:如果DEFINER='admin'@'localhost',而当前登录用户没有SET USER权限或不是admin,就会报ERROR 1419 (HY000): You do not have the SUPER privilege...。
实操建议:
- 开发阶段尽量用
SQL SECURITY INVOKER创建过程,避免依赖DEFINER权限,也更符合最小权限原则 - 如果必须用
DEFINER,确保创建者拥有CREATE ROUTINE+ALTER ROUTINE+EXECUTE(对自己)权限,且 MySQL 配置中未启用sql_mode=NO_AUTO_CREATE_USER(已弃用,但旧环境可能残留) -
SHOW CREATE PROCEDURE proc_name;可查当前DEFINER和SQL SECURITY设置
常见错误:PROCEDURE does not exist但明明能SHOW PROCEDURE STATUS
这不是权限问题,是作用域问题。典型场景:用户A在db1里创建了proc_test,但连接时没指定库(即当前DATABASE()为空),然后直接执行CALL proc_test()——MySQL会去默认库(或mysql系统库)找,当然找不到。
实操建议:
- 调用时务必带库名:
CALL db1.proc_test();,这是最稳妥写法 - 连接后先
USE db1;再CALL proc_test();,但要注意:如果过程里用了跨库表操作,USE不会改变其内部SQL的默认库上下文 -
CALL不支持变量传库名,所以动态库名调用必须用预处理语句+CONCAT拼接,且调用者需额外有对应库的EXECUTE权
权限变更后,已打开的连接为什么还不生效?
MySQL 的权限检查发生在每次语句执行前,但「连接会话」不会自动重载权限元数据。也就是说,你在另一个会话里给用户加了EXECUTE权,当前正在跑应用的连接仍会报错,直到它断开重连,或主动执行 FLUSH PRIVILEGES;(其实没必要)——更准确地说,是会话缓存了初始权限快照。
实操建议:
- 上线前确认应用连接池配置了
autoReconnect=true或类似机制(如 HikariCP 的connection-test-query),否则权限更新后老连接永远卡死 - 测试时别只在一个客户端验证,新开一个
mysql -u user -p连接再试,避免被复用会话误导 - 如果用的是代理(如 ProxySQL、MaxScale),还要确认代理层是否缓存了权限映射关系
权限粒度比想象中细:同一个过程,对不同用户可以开/关EXECUTE;但一旦开了,就默认允许该用户读取过程定义(SHOW CREATE PROCEDURE),没法单独屏蔽——这点常被忽略。











