MySQL 5.7 备份恢复后函数与存储过程丢失:原因分析与正确备份姿势

一、问题背景:备份恢复了,函数和存储过程却没了

在 MySQL 5.7 环境中,很多同学会遇到一个非常"反直觉"的现象:备份和恢复流程看起来完全正常,但恢复完成后,库里的函数、存储过程却全部丢失了。更让人困惑的是,备份文件本身并没有报错,恢复过程也没有任何异常提示。

本文从官方文档出发,先说明这个问题的成因,再通过"错误示范"和"正确示范"两组实操对比,给出可以直接落地的备份脚本与验证方法。

二、原因分析:为什么 mysqldump 会"丢"存储过程

先看官方文档给出的两条关键结论:

  • 默认情况下,mysqldump 和 mysqlpump 都不会转储 sys 模式,详见 sys Schema Usage。
  • mysqldump 默认不转储 INFORMATION_SCHEMA、performance_schema 和 sys schema,详见 mysqldump。

也就是说,官方文档明确告诉我们:不会备份 sys 库 。但真正的问题并不止于此------在使用 mysqldump --all-databases 生成的备份 SQL 文件内部,会包含清空 mysql.proc 的语句,导致恢复后存储过程无法正常使用。这是一个 bug,并且只存在于 MySQL 5.7.x;MySQL 8.0.x 及 8.4 以上版本没有这个问题。

复制代码
5.7版本,正常的备份恢复,会导致MySQL中的函数、存储过程丢失。
在MySQL官档中:
	默认情况下,mysqldump和mysqlpump都不会转储sys模式。
	https://dev.mysql.com/doc/refman/5.7/en/sys-schema-usage.html
	mysqldump默认不转储"INFORMATION_SCHEMA"、"performance_schema" 和 "sys schema"。
	https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
官方文档明确的告诉我们不会备份 sys 库。
但在使用 mysqldump 在执行 --all-databases 生成的备份sql文件内部会清空 mysql.proc 导致 存储过程 无法正常使用;
这是一个bug,并且只存在于 MySQL 5.7.x 
MySQL 8.0.x ,MySQL8.4以上版本没有这个问题(根据官方文档介绍MySQL 8.0 及以后版本:MySQL 进行了数据字典(Data Dictionary)重构)
需要注意的是,mysql.proc 表的存在与 MySQL 的版本密切相关:
MySQL 5.7 及更早版本:mysql.proc 是一个真实的物理系统表(早期使用 MyISAM 引擎,MariaDB 10.4+ 使用 Aria 引擎),可以直接被查询和操作。
MySQL 8.0 及以后版本:MySQL 进行了数据字典(Data Dictionary)重构,原有的  mysql.proc  物理表被移除,元数据统一迁移至基于 InnoDB 引擎的内部数据字典中(如 mysql.routines 和 mysql.parameters)。为了向后兼容,MySQL 8.0 提供了一个同名的只读视图,但不再推荐直接访问。
mysql> select count() from mysql.proc;    --5.7版本(包括刚刚从5.7升级到8.0的情况,过一段时间这个表自动消失)正常情况下这里有数据
+----------+
| count() |
+----------+
|       48 |
+----------+
1 row in set (0.00 sec)

正确做法
select_databases="SELECT GROUP_CONCAT(schema_name SEPARATOR ' ') FROM INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME NOT IN ('performance_schema','information_schema');"
db_list=mysql --login-path=root -NBe "$select_databases"
echo $db_list
执行备份
mysqldump --login-path=root -R -F --master-data=2 --single-transaction --max_allowed_packet=1024M --log-error=mysqldump_error.log --databases $db_list --triggers --routines --events 2> /dev/null | gzip  > all_bak_date +%Y%m%d.sql.gz
单独备份sys/mysql模式
/usr/local/mysql/bin/mysqldump -uroot -p****** --databases sys --single-transaction --triggers --routines --events --result-file=/backup/sys_date +%Y%m%d.sql
/usr/local/mysql/bin/mysqldump -uroot -p'123qqq...A' --databases mysql --single-transaction --triggers --routines --events --result-file=/backup/mysql_date +%Y%m%d.sql
验证备份
grep "Current Database" all_bak_date +%Y%m%d.sql
egrep "USE `mysql`;|IF EXISTS `proc`;|INSERT INTO `proc` VALUES" all_bak_date +%Y%m%d.sql

三、版本差异:mysql.proc 表的前世今生

需要注意的是,mysql.proc 表的存在与 MySQL 的版本密切相关:

  • MySQL 5.7 及更早版本 :mysql.proc 是一个真实的物理系统表(早期使用 MyISAM 引擎,MariaDB 10.4+ 使用 Aria 引擎),可以直接被查询和操作。
  • MySQL 8.0 及以后版本 :MySQL 进行了数据字典(Data Dictionary)重构,原有的 mysql.proc 物理表被移除,元数据统一迁移至基于 InnoDB 引擎的内部数据字典中(如 mysql.routines 和 mysql.parameters)。为了向后兼容,MySQL 8.0 提供了一个同名的只读视图,但不再推荐直接访问。

因此,在 5.7 上排查问题时,可以直接查询 mysql.proc 确认存储过程数量:

select count() from mysql.proc;

错误示范(--all-databases)

正确示范(单独指定databases)

复制代码
[root@itpuxdb01 ~]# cat mysql_backup.sh 
select_databases="SELECT GROUP_CONCAT(schema_name SEPARATOR ' ') FROM INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME NOT IN ('performance_schema','information_schema');"
db_list=mysql -uroot -p'******' -h127.0.0.1 -P3306 -NBe "$select_databases"
echo ========================
echo $db_list
echo ========================
mysql 5.7.25 mysql.proc
/usr/local/mysql/bin/mysqldump -uroot -p'******' -h127.0.0.1 -P3306 

-R -F --master-data=2 --single-transaction --max_allowed_packet=1024M 

--log-error=mysqldump_error.log --databases $db_list 

--triggers --routines --events --hex-blob > all_bak_date +%Y%m%d.sql
如果要压缩添加以下参数
--log-error=mysqldump_error.log 

2> /dev/null | gzip  > all_bak_date +%Y%m%d.sql.gz
单独备份sys/mysql模式
/usr/local/mysql/bin/mysqldump -uroot -p'' --databases sys --single-transaction --triggers --routines --events --result-file=/backup/sys_date +%Y%m%d.sql
/usr/local/mysql/bin/mysqldump -uroot -p'' --databases mysql --single-transaction --triggers --routines --events --result-file=/backup/mysql_date +%Y%m%d.sql
验证备份
grep "Current Database" all_bak_20261024.sql
egrep "USE `mysql`;|IF EXISTS `proc`;|INSERT INTO `proc` VALUES" all_bak_20261024.sql

四、mysqldump8.0 全备还原仍有几个容易踩的坑

但 8.0 全备还原仍有几个容易踩的坑

  1. mysqldump --all-databases 默认不导出存储过程/函数/事件
    必须显式加 --routines --events,否则还原后业务库的存储过程、函数、事件会丢失。
  2. sys 库本身默认也不被 mysqldump 导出
    官方文档明确说明 mysqldump / mysqlpump 默认不 dump sys schema。 不过 8.0 的 sys 视图是纯 SQL 视图,不依赖 mysql.proc 里的 routines,所以不会出现 5.7 那种 ERROR 1356 连锁失效。
  3. DEFINER 权限问题更常见
    8.0 对 DEFINER 校验更严格,如果备份里有 DEFINER='xxx'@'yyy' 而目标库没有该用户,导入会报 ERROR 1449 或 ERROR 1227。可以用 --skip-definer(8.0.26+)或导入前建好对应用户。

8.0 推荐的全备命令

复制代码
/usr/local/mysql/bin/mysqldump --all-databases \
  --set-gtid-purged=OFF \
  -R -F --source-data=2 \
  --single-transaction \
  --routines \
  --events \
  --triggers \
  --hex-blob \
  --max_allowed_packet=256M \
  --log-error=mysqldump_error.log \
  2> /dev/null | gzip  > all_bak_`date +%Y%m%d`.sql.gz

如果你还希望 sys 库也一起备份(虽然 8.0 不必须),可以额外:
/usr/local/mysql/bin/mysqldump --databases --routines sys > sys_dump.sql

五、一句话总结

  • 5.7:mysqldump -A 还原会清空 mysql.proc → sys 库失效,是已知 bug。
  • 8.0+:mysql.proc 已移除,该 bug 不存在;但要注意加 --routines --events,以及 DEFINER 权限兼容性。
相关推荐
GottdesKrieges2 小时前
Redis哨兵模式新建用户和修改口令
数据库·redis
二宝哥3 小时前
02.springboot项目对接国内模型实现对话聊天
数据库·人工智能·spring boot
秦时明月之君临天下4 小时前
MySQL purge 参数详解:innodb_purge_threads 与 innodb_purge_batch_size
数据库·mysql·1024程序员节
三垣网安4 小时前
某某大学心理健康教育平台弱口令及SQL注入漏洞
数据库·sql
打工仔折腾 AI4 小时前
AI Agent 工程化实战(二):5 分钟跑通 Deep Agent 并逐层拆解底层链路
java·数据库·人工智能·后端·python·langchain·ai agent 实战
Shaoshing4 小时前
MySQL视图
数据库
努力努力再努力wz5 小时前
【C++ 高阶系列】C++ 高性能网络编程:当 Reactor 遇见协程:从 epoll 回调到异步 MySQL,彻底打通任务挂起与恢复
网络·c++·mysql
这个DBA有点耶5 小时前
测试全绿,上线三周数据没入账——那个95%的兼容度报告,漏掉的是边界
数据库·mysql·架构
1024奇点5 小时前
【仓颉语言入门 · 第二篇 第 15 课】
开发语言·数据库·ide·开源