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 权限兼容性。
相关推荐
csdn_aspnet8 小时前
macOS 10 、Docker 玩轉 MySQL
运维·mysql·macos·docker·容器·mac
flash俊杰9 小时前
v0.5-01 让桌面 AI 助手记得住:预算组装、递归摘要、长期记忆与评估基线
数据库·安全·架构
王中阳Go9 小时前
100 件货卖出 116 件,库存停在 -16
后端·mysql·go
2501_933923259 小时前
redis:string类型常见命令
数据库·redis·缓存
byte轻骑兵11 小时前
时序数据库选型指南:Apache IoTDB 社区版实践与踩坑
数据库·人工智能·apache·时序数据库·iotdb
黄连木笛11 小时前
Redis Insight 汉化教程:Windows / macOS / Linux 设置中文界面(附繁體、教程汉化、关闭自动更新)
数据库·redis·缓存
nice_lcj52011 小时前
MySQL 存储引擎入门:InnoDB 和 MyISAM 到底怎么选
java·数据库·mysql·面试·innodb·存储引擎·myisam
古典和浪漫12 小时前
MVCC机制
数据库
xixingzhe213 小时前
mysql全量、增量备份
数据库·mysql
AllData公司负责人20 小时前
AI大模型数据开发底座系列说明书,AllData集成Chat2DB开源项目建设AI 数据库分析底座,涵盖AI 洞察/对话SQL/智能视图!
数据库·人工智能·sql·开源·ai 洞察·对话sql