导读:本期聚焦于森沢创作的《MySQL CREATE ROUTINE权限如何正确授予与撤销?附代码实例详解》,敬请观看详情。存储过程建到一半报ERROR 1370,是语法错了还是权限没给够?如果你只授予了CREATE、INSERT、UPDATE,仍然无法执行CREATE PROCEDURE,问题大概率出在CREATE ROUTINE权限上。CREATE ROUTINE是MySQL专门用来控制存储过程和存储函数创建的权限,与建表的CREATE权限相互独立,不能混为一谈。本文通过一个完整的授权实例演示如何用GRANT语句为普通用户授予routine_demo库下的CREATE ROUTINE权限,再创建存储过程、追加EXECUTE权限并调用,最后用REVOKE回收创建能力。同时介绍mysql.user、mysql.db和information_schema.SCHEMA_PRIVILEGES中查看权限的方法,帮助读者理解权限存储位置,并给出生产环境中业务账号与发布账号拆分授权的最佳实践,避免因权限过宽带来的安全风险。

在MySQL中创建存储过程或者存储函数,很多时候并不是语法问题,而是权限配置挡住了流程。有一个专门的权限叫 CREATE ROUTINE,很多同学只给 CREATE、INSERT、UPDATE,到了执行 CREATE PROCEDURE 时还是收到权限报错。这个权限与建表的 CREATE 并不等价,它单独控制例程对象的创建。

MySQL CREATE ROUTINE权限如何正确授予与撤销?附代码实例详解

一、CREATE ROUTINE权限与CREATE权限的关系

MySQL的权限粒度在例程层面设计得比较细。创建表依赖 CREATE 权限,创建视图依赖 CREATE VIEW,创建存储过程和函数则依赖 CREATE ROUTINE。也就是说,即使你拥有某个库的 CREATE 权限,也只代表可以建表,不能推断你可以建存储过程。两者在内部存储到不同的授权列中,比如全局用户表里的 Create_priv 和 Create_routine_priv 就是分开的。

可以通过 SHOW PRIVILEGES 查看MySQL支持的权限列表,里面会列出 Create routine 的上下文为数据库、表或全局。这个权限不允许按某个具体的存储过程授权,只能全局授权,或者授权到某个数据库下,意味着该数据库下所有例程的创建动作都受它控制。

理解这一点后,排查问题就简单了:如果一个账号在测试库建表正常,但创建存储过程报错,优先检查 mysql.db 表中该账号所在库的 Create_routine_priv 列,而不是只看 Create_priv。

-- 查看MySQL支持的所有权限
SHOW PRIVILEGES;

-- 查看用户级权限
SELECT User, Host, Create_priv, Create_routine_priv
FROM mysql.user
WHERE User = 'routine_user';

二、完整授权与撤销实例:从建用户到创建存储过程

下面使用一个独立数据库 routine_demo 和一个最小权限账号 routine_user 进行演示。先创建数据库和用户,再只授予 CREATE ROUTINE 权限,不做全库授权。这样可以观察权限是否真正够用。

执行授权时,MySQL 8.0 的 GRANT 语句要求用户已经存在,所以需要先 CREATE USER。如果是在 MySQL 5.7 上,GRANT 可以隐式建用户,但新版本已经移除了这个行为。授权完成后,用 SHOW GRANTS 确认当前账号拥有的权限,亮出最小权限集合。

-- 以root或具有创建权限的管理账号执行
CREATE DATABASE IF NOT EXISTS routine_demo;

CREATE USER IF NOT EXISTS 'routine_user'@'localhost' IDENTIFIED BY 'Str0ngPass!';

GRANT CREATE ROUTINE ON routine_demo.* TO 'routine_user'@'localhost';

SHOW GRANTS FOR 'routine_user'@'localhost';

接着切换到 routine_user 账号登录,并尝试创建一个只返回固定结果的存储过程。这里不需要访问任何业务表,因此可以排除表权限的干扰。只要 CREATE ROUTINE 权限存在,下面的语句就应该执行成功。

-- 使用 routine_user@localhost 登录后执行
USE routine_demo;

DELIMITER $$

CREATE PROCEDURE hello_world()
BEGIN
    SELECT 'hello' AS msg;
END$$

DELIMITER ;

创建成功只代表例程对象已经存在。要调用它,还必须有 EXECUTE 权限。很多时候业务账号需要调用存储过程,但不应该拥有创建和修改例程的权限。此时管理账号可以单独追加 EXECUTE 授权。

-- 回到管理账号,追加调用权限
GRANT EXECUTE ON routine_demo.* TO 'routine_user'@'localhost';

-- 切换回 routine_user 账号测试调用
CALL routine_demo.hello_world();

如果希望回收创建能力,只保留调用能力,可以使用 REVOKE。回收后,同一个账号再次执行 CREATE PROCEDURE 会收到类似 ERROR 1370 (42000): create routine command denied to user 的错误。

-- 管理账号执行
REVOKE CREATE ROUTINE ON routine_demo.* FROM 'routine_user'@'localhost';

-- 再使用 routine_user 执行创建会失败,报错信息与CREATE ROUTINE权限缺失有关

三、从授权表和information_schema查看CREATE ROUTINE权限状态

权限信息不只在 SHOW GRANTS 里可以看到,它也会落到系统表中。全局权限保存在 mysql.user,数据库级权限保存在 mysql.db。对于只授权到 routine_demo.* 的场景,mysql.user 中的 Create_routine_priv 应该是 N,而 mysql.db 中的 Create_routine_priv 为 Y。

这种分表存储的方式很容易让人误判,因为只看 mysql.user 会以为用户没有权限,但实际在目标数据库上它是有创建例程能力的。所以授权排错时,建议同时查询两张表,或直接使用 information_schema 中的权限视图。

-- 查询用户级权限
SELECT User, Host, Create_routine_priv
FROM mysql.user
WHERE User = 'routine_user';

-- 查询数据库级权限
SELECT User, Host, Db, Create_routine_priv
FROM mysql.db
WHERE User = 'routine_user';

下面的语句通过 information_schema.SCHEMA_PRIVILEGES 查看账号在 routine_demo 库上的权限,结果会把 CREATE ROUTINE 和 EXECUTE 都列出来。与系统表相比,这种查询更直观,也不用担心手工连接用户和主机列时出错。

SELECT GRANTEE, TABLE_SCHEMA, PRIVILEGE_TYPE
FROM information_schema.SCHEMA_PRIVILEGES
WHERE GRANTEE LIKE 'routine_user%';

四、生产环境中的权限拆分实践与常见列外

生产环境不建议给业务账号直接授予 CREATE ROUTINE。存储过程的创建和变更应交给发布系统或专门的变更账号,业务账号只需要 EXECUTE,这样即使业务代码出现漏洞,攻击者也无法通过创建恶意例程来持久化。常见做法是把权限拆成两类:变更账号拥有 CREATE ROUTINE、ALTER ROUTINE 和 DROP,业务账号只拥有 EXECUTE。

-- 业务账号:只负责读写和调用例程
CREATE USER IF NOT EXISTS 'app_user'@'%' IDENTIFIED BY 'AppPass123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'%';
GRANT EXECUTE ON app_db.* TO 'app_user'@'%';

-- 发布账号:只负责维护存储过程、函数
CREATE USER IF NOT EXISTS 'deploy_user'@'%' IDENTIFIED BY 'DeployPass456!';
GRANT CREATE ROUTINE, ALTER ROUTINE ON app_db.* TO 'deploy_user'@'%';

另一个容易混淆的权限是 ALTER ROUTINE。它只控制修改或删除例程的属性,例如修改存储过程的注释、SQL SECURITY 等,或者重新定义函数行为。很多同学以为有 CREATE ROUTINE 就能改自己的存储过程,实际执行 ALTER PROCEDURE 时却报错,原因就是缺少 ALTER ROUTINE。

创建存储函数时,还会受到 log_bin_trust_function_creators 参数影响。该参数默认开启情况下不允许创建可能不安全的函数,除非创建者拥有 SUPER 权限。如果业务确实需要在主库创建函数,可以在会话级设置该参数,或者严格审查函数是否会破坏主从一致性。这个限制与 CREATE ROUTINE 是两个不同层面的问题,排查时要分开看。

-- 查看当前是否信任函数创建者
SHOW VARIABLES LIKE 'log_bin_trust_function_creators';

-- 在会话级临时允许创建函数
SET GLOBAL log_bin_trust_function_creators = 1;

总结来说,CREATE ROUTINE 是MySQL例程权限体系中的第一道门槛。授权时先明确账号是用于普通业务调用,还是用于发布变更,再决定授予 EXECUTE 还是 CREATE ROUTINE、ALTER ROUTINE。出现 ERROR 1370 时,先查 SHOW GRANTS 和 information_schema.SCHEMA_PRIVILEGES,一般就能定位到问题。这样既满足最小权限原则,也能减少线上误操作。

CREATE ROUTINE权限MySQL存储过程GRANT授权修改时间:2026-09-27 03:00:29

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0927/62387.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。