1. 为什么我坚持用命令行导出数据库先交代一下背景。我接手过不少项目的数据库运维发现一个现象很多开发同学用 Navicat 或者 DataGrip 这类图形化工具用得飞起鼠标点几个按钮就能把库导出成 SQL 文件看起来挺方便。但真到了生产环境尤其是 Linux 服务器上没有图形界面、没有 GUI 工具、带宽有限甚至有时候你连 FTP 都传不出去这时候唯一能依靠的就是命令行。我自己第一次被命令行“逼上梁山”是在多年前当时负责一个电商系统的库存库备份。那个库不大也就 2GB 左右但 Navicat 导出到一半就断重试了三次都不行。后来到服务器上用 mysqldump 一次性成功压缩之后才 300 多MB用 scp 拉下来也就几分钟的事。从那次之后但凡涉及数据库备份、迁移、导出我第一反应永远是命令行图形工具只是辅助。这篇文章要讲清楚的就是 MySQL 命令行导出数据库的完整实战。如果你属于下面这几类人建议认真看完刚接触 MySQL不知道除了图形界面还能怎么把数据弄出来已经在用 mysqldump但只会背一条最简单的命令遇到只导结构、只导某张表、只导某几个字段这种需求就卡住需要在服务器上做定时备份想搞一个能直接跑起来的脚本遇到过导出后中文乱码、权限报错、导入时数据类型对不上这类问题想搞明白根因。我会从原理讲到实操再给出几种不同场景的命令组合最后补充常见的坑和排查思路。内容不绕弯子每一条命令都是我实际跑过的。2. mysqldump 工作机制它在底层到底做了什么很多人用 mysqldump 的时候是“背命令”的心态知道mysqldump -u root -p123456 dbname backup.sql能导出但不知道为什么是这么写的也不知道导出文件里那些CREATE TABLE、LOCK TABLES、INSERT INTO是什么意思。先从底层拆一下。mysqldump 本质上是一个客户端程序它通过 MySQL 协议和你指定的服务器建立连接然后执行一系列操作最终把结果输出到标准输出stdout。之所以命令末尾会有重定向就是因为它默认是往屏幕上打印你用重定向符号把输出接进文件里。导出过程中它做了这几件关键的事情获取表结构信息。它调用SHOW CREATE TABLE获取每张表的建表语句保证你在另一台机器上导入时能原样重建表结构包括字段类型、默认值、索引、外键约束、字符集。读取表数据。默认情况下是逐行SELECT * FROM 表名读取然后把结果拼成一条条INSERT INTO语句写入导出文件。处理一致性。如果你不指定任何参数mysqldump 会默认加上LOCK TABLES也就是在导出当前表的时候把这张表锁住防止导出过程中数据发生变化保证导出的是一个时间点的快照。如果加上--single-transaction则会改用 InnoDB 的事务隔离机制通过START TRANSACTION WITH CONSISTENT SNAPSHOT拿到一致性的快照不需要锁全表。记录 binlog 位置信息可选。某些场景下你需要导出文件里带上 binlog 文件名和位置方便做主从复制这时候用--master-data参数。理解了这个机制再看命令就容易了。mysqldump -u 用户名 -p 密码 数据库名这几个部分是建立连接用的后面跟着的才是控制导出行为的参数。提示MySQL 8.0 开始mysql_native_password插件默认被弃用如果你是 8.0 以上版本连接时注意用户使用的认证插件。早期版本导出的用户连接不上新库多半跟这个有关。另外两个常见的“怪现象”也能解释通了。第一为什么导出的 SQL 文件打开后看到很多/*!40101 SET ... */这样的注释这是 MySQL 的版本条件执行语法。40101表示该行在 MySQL 版本高于 4.01.01 时生效。这样做的好处是同一个导出文件在低版本和高版本 MySQL 中导入时都能自动跳过不支持的语法提高兼容性。第二为什么导出的文件很大反而比原来的库小很多因为 SQL 文件是文本文件里面是插入语句而原始表数据在磁盘上可能是 InnoDB 页面格式每页 16KB存在碎片、填充、索引空间文本表达未必比二进制多。加上压缩后变化更大后面我会给一个压测过的实际数据。3. 从零到一最常用的导出命令与参数拆解3.1 单库导出基础命令的参数含义先来最基本的命令mysqldump -h 127.0.0.1 -P 3306 -u root -p mydb mydb.sql执行后会提示输入密码密码不会显示在命令行里这是安全习惯别把密码直接写在命令里因为history会记录下来。这条命令做了什么连接本机 3306 端口的 MySQL用 root 身份导出 mydb 整个库的所有表结构和数据输出到 mydb.sql。有几个细节值得展开-h什么时候该写什么时候可以不写。默认情况下 mysqldump 连接的是 localhost会走 Unix Socket而不是 TCP/IP。你在本机执行不写-h也很快但只要涉及网络连接就必须写-h指定主机。这里有个常见的坑服务器上 MySQL 没开 socket 文件或者 socket 路径不一致会报Cant connect to local MySQL server through socket。这时你可以强制走 TCP用--protocoltcp -h 127.0.0.1。-P是端口小写-p是密码。大写 P 后面跟数字小写 p 后面跟密码字符串两者写法非常容易混我见过不止一个同事把大小写搞反报错报得莫名其妙。3.2 只导结构或只导数据有时候你不想把所有东西都导出来比如要迁移到新环境表结构已经建好了只需要数据或者反过来只要建表语句不想带数据。# 只导表结构不导数据 mysqldump -u root -p -d mydb mydb_schema.sql # 只导数据不导表结构 mysqldump -u root -p -t mydb mydb_data.sql-d是--no-data的简写-t是--no-create-info的简写。这两个参数使用频率非常高尤其是做增量环境同步时经常需要“结构全量数据部分”的组合。3.3 多库导出与单表导出导出多个库不需要写多个命令用--databases参数即可mysqldump -u root -p --databases db1 db2 db3 multi.sql注意--databases和直接跟在命令后面的单库名是有区别的。加了--databases导出文件里会包含CREATE DATABASE IF NOT EXISTS和USE db1语句导入时不需要手动创建库不加则只有表和数据的语句导入前必须确保目标库存在。单表导出也很常见mysqldump -u root -p mydb users users.sql表名直接接在库名后面。如果要导出多张表可以继续追加mysqldump -u root -p mydb users orders users_orders.sql这个方式适合只同步大库中的部分核心表比如订单库几十 GB每天只需要把 orders 和 order_items 两张表导出做统计就不需要动整个库。3.4 带条件的部分数据导出这个需求也很常见比如只导出某个时间段的订单、只导出某个用户分组的数据。mysqldump 提供了--where参数mysqldump -u root -p mydb orders --wherecreate_time 2024-01-01 AND create_time 2025-01-01 orders_2024.sql注意--where的 SQL 条件要符合你的目标 MySQL 版本的语法。有一次我在条件里用了 MySQL 8.0 才支持的写法结果拿到 5.7 的实例上导入直接语法错误。这是个真实教训导出的目标环境版本你必须在写命令前确认。3.5 压缩导出解决大库导出慢、文件大的方案大库导出最大的痛点是文件太大、写盘慢、传输出慢。解决方案很简单——导出时直接压缩。mysqldump -u root -p mydb | gzip mydb.sql.gz数据经管道直接走 gzip 压缩不需要先把未压缩的 SQL 文件写到磁盘再压缩省一份磁盘空间和时间。实际项目中一个 5GB 的 InnoDB 库导出的 SQL 文件大约 3.8GBgzip 压缩后不到 700MB。压缩耗时大约在 20 秒到 1 分钟之间取决于 CPU 性能但换来的是传输时间大幅缩短。解压导入时用gunzip mydb.sql.gz | mysql -u root -p mydb3.6 核心参数对照表我刚学 mysqldump 时最烦的就是一堆参数记不住这里列一个高频参数对照表建议收藏参数简写作用典型使用场景--all-databases-A导出所有库全实例迁移、整机备份--databases-B导出指定多个库多库备份--no-data-d只导结构新环境初始化 DDL--no-create-info-t只导数据数据迁移--single-transaction无InnoDB 一致性快照不锁表在线备份--lock-tables-l导出前锁定所有表MyISAM 表备份--where-w按条件导出部分数据导出--routines-R包含存储过程和函数迁移完整库--triggers无包含触发器迁移完整库--events-E包含事件调度器迁移完整库--master-data无记录 binlog 位置搭建从库--set-gtid-purged无控制 GTID 记录MySQL 8.0 主从复制其中--routines、--triggers、--events是很多人忽略的。默认情况下 mysqldump 不导出存储过程、函数、触发器和事件如果你只执行裸命令mysqldump -u root -p dbname out.sql这些数据库对象全部丢失。等你在新环境跑起来发现业务报错“存储过程不存在”那就晚了。我的习惯是只要目标是“完整迁移一个库”这三个参数一定带上。4. 只导数据还是连结构一起不同导出方案的取舍mysqldump 不是唯一的导出方案。根据不同场景我在项目里会换用不同的工具和方式这里对比一下方便你按需选型。4.1 mysqldump通用性最强优点跨版本兼容性最好、逻辑备份人类可读、最关键的是——它是标准命令行工具所有 MySQL 环境都自带不需要额外安装。缺点速度一般尤其是大数据量时单线程逐行读取再生成 INSERT 语句性能有瓶颈。适用场景中小库5GB 以下、迁移后可能需要人工检查数据的场景、定时备份脚本。4.2 mysqlpump多线程并行导出MySQL 5.7 开始提供了 mysqlpump最核心的改进是支持并行导出速度比 mysqldump 快不少。mysqlpump -u root -p --parallel-schemas4:db1,db2 -B mydb mydb_pump.sql--parallel-schemas可以指定并发线程数。我在一个 20GB 的库上做过对比mysqldump 大约跑了 12 分钟mysqlpump 并行度调到 8时间压缩到 4 分半。不过 mysqlpump 的导出文件格式跟 mysqldump 略有差异导入时兼容性也稍弱如果你下游的工具只认 mysqldump 的输出就要权衡一下。4.3 SELECT INTO OUTFILE快速导出为 CSV/TXT如果需要导出结果给数据分析、报表系统用直接用 SQL 语句导出为文本也是一种“导出数据库”的姿势。mysql -u root -p -e SELECT id, user_name, amount FROM mydb.orders WHERE create_time 2024-01-01 mydb orders.csv或者用 MySQL 原生的 OUTFILESELECT id, user_name, amount FROM orders INTO OUTFILE /tmp/orders.csv FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY ;注意 OUTFILE 有几个硬性限制MySQL 进程必须有操作系统层面的文件写入权限secure_file_priv变量如果配置了只能导出到指定目录导出的文件在 MySQL 服务器本机不在客户端。这点经常搞混有人本机执行 OUTFILE 却在自己电脑上找文件当然找不到。4.4 冷备份直接复制数据目录极端场景下比如要冷迁移整个 MySQL 实例物理备份反而是最快的。步骤是停库把整个datadir打包压缩传到目标机器初始化目录权限再启库。# 停库 systemctl stop mysqld # 打包数据目录假设 datadir/var/lib/mysql tar zcf mysql_datadir_backup.tar.gz /var/lib/mysql # 启动 systemctl start mysqld优点速度最快几乎没有逻辑层的转换开销。缺点必须停机目标实例的版本、系统架构、路径结构都可能影响可恢复性如果要做部分表恢复会非常痛苦。4.5 选型决策逻辑我个人在处理导出问题时会先问自己三个问题导出去做什么用——如果是交给别人导入环境用 mysqldump/mysqlpump 的逻辑备份如果是给数据分析团队拉数据用 OUTFILE 导 CSV。数据量有多大——10GB 以内无脑 mysqldump10GB 以上考虑 mysqlpump 并行百 GB 级别就要规划逻辑备份的时间窗口或者考虑物理备份/其他方案。是否允许锁定——在线业务库必须用--single-transaction不能默认的锁表。这套判断逻辑是我从多次事故里总结出来的。最开始我只用 mysqldump第一次做 30GB 库的全量导出直接把线上订单接口拖慢了因为默认锁表MyISAM 表读都读不了。后来养成了先查询存储引擎再决定参数的职业习惯。5. 恢复导入导出只是前戏能导回去才是完整闭环很多文章只讲导出不讲导入但在实际运维中导出和导入永远是一个整体。你花大半天导出的文件如果导入时报错那个滋味比导出失败还难受。这里我先讲最常用的导入方式再讲典型坑。5.1 基础导入命令mysql -u root -p mydb mydb.sql如果导出的文件包含CREATE DATABASE语句即用了--databases参数目标端不需要先建库直接mysql -u root -p mydb.sql注意了这里的区别很容易被忽略。不加-D指定数据库直接读文件执行文件头部的CREATE DATABASE IF NOT EXISTS xxx会自动创建库。但如果导出时没加--databases文件里没有建库语句你就得先手动建库mysql -u root -p -e CREATE DATABASE IF NOT EXISTS mydb CHARACTER SET utf8mb45.2 导入速度优化的三把武器几个优化导入的参数亲测有效大文件导入能差出几倍时间mysql -u root -p --max_allowed_packet512M mydb mydb.sql mysql -u root -p --init-commandSET FOREIGN_KEY_CHECKS0 mydb mydb.sql mysql -u root -p --init-commandUNIQUE_CHECKS0 mydb mydb.sql--max_allowed_packet调大避免单条INSERT ... VALUES (...)因为包太大而报Packet Too Large的错误。FOREIGN_KEY_CHECKS0在导入期间关闭外键检查可以避免因为表导入顺序导致的约束校验失败。UNIQUE_CHECKS0则是关闭唯一索引检查导入完再恢复减少索引维护开销。这里提一个我自己常用的组合拳先把导入文件里的所有INSERT语句合并成批量插入形式。mysqldump 默认按较大块批量输出但如果你拿到的文件是单条单条 INSERT比如某些工具导出的导入会非常慢。这种情况下可以先直接导如果慢得离谱再用脚本把 SQL 文件中的连续 INSERT 合并成多值形式。实测 100 万行数据单条 INSERT 导入需要 18 分钟合并后 11 分钟少了接近一半。5.3 导入过程中的常见报错定位逻辑报错一Unknown databaseERROR 1049 (42000): Unknown database mydb原因很简单导出文件没有包含建库语句而目标库没建。解决先建库再导入或者用带--databases导出的文件。报错二Table already exists然后中断这个我遇到的情况一般是两种一是目标库已经存在同名表而导入过程没有DROP TABLE二是导出文件里每条CREATE TABLE前面没有IF NOT EXISTS导致已存在的表直接报错。处理方式是在目标端先清库或者导入前用参数指定mysql -u root -p -e DROP DATABASE IF EXISTS mydb; CREATE DATABASE mydb CHARACTER SET utf8mb4;这样最干净但操作前千万确认你连的是目标库不是生产库。我见过同事在测试环境写对了在生产环境写错了库名一条DROP DATABASE直接把正库干掉。这种操作建议每次执行前把命令里的库名再读三遍。报错三Data too long for column...导入时数据类型对不上通常是因为两端表结构定义不一致。这个问题的根源有时候是当初导出时用的库是旧版本的比如 varchar 在某些排序规则下对字符长度的计算方式不同。最稳妥的做法是导出结构和导入结构保持一致不要只导数据结构也一起导。6. 字符集、权限与阻塞导出时绕不开的三个头疼问题6.1 字符集导致的乱码问题导出文件是文本文件字符集处理不好导入后中文全变问号。我的建议是导出和导入两端都明确指定字符集mysqldump -u root -p --default-character-setutf8mb4 mydb mydb.sql mysql -u root -p --default-character-setutf8mb4 mydb mydb.sql为什么是utf8mb4而不是utf8因为 MySQL 的utf8实际最多支持 3 字节编码存不了 emoji 表情和一些特殊字符。而utf8mb4兼容完整的 Unicode是 MySQL 8.0 的默认字符集。如果你的库建得早可能是 utf8 或 latin1导出前先查一下SHOW CREATE DATABASE mydb; SHOW CREATE TABLE mydb.users;查看结果里的DEFAULT CHARSET字段然后用对应的字符集导出可以避开很多乱码。如果只是你本地查看导出文件内容觉得中文乱码并不代表文件本身有问题。用编辑器打开时要设置正确的编码格式比如 VSCode 里那个右下角的编码切换要选择 UTF-8 而不是 Windows 的 GBK。我第一年做迁移时在这个上面浪费了半个多小时一度以为数据导坏了后来发现是编辑器显示问题。6.2 权限问题为什么明明能连 MySQLmysqldump 还是失败常见报错ERROR 1045 (28000): Access denied for user backuplocalhost根源在于 mysqldump 需要执行的语句比普通 SELECT 多它要SHOW VIEW权限拿到视图定义、RELOAD权限做FLUSH TABLES、PROCESS权限查进程列表如果导出包括存储过程还要SELECT权限范围内能查到mysql.proc表不同版本权限体系有差异。如果业务账号只是拿来日常查询的拿它做全量备份几乎必然报权限不足。正确做法是单独建一个备份账号给它最小化但完整的备份权限CREATE USER backuplocalhost IDENTIFIED BY backup_pass; GRANT SELECT, SHOW VIEW, RELOAD, LOCK TABLES, PROCESS, TRIGGER ON *.* TO backuplocalhost; FLUSH PRIVILEGES;注意RELOAD和LOCK TABLES是全局权限*.*才能授予。每次新建备份任务我都用这个模板十年了没出过权限问题。6.3 导出期间会不会影响线上业务这是被问得最多的问题答案取决于存储引擎和参数如果全是 InnoDB加--single-transaction即可。它基于 MVCC 快照读取导出期间不阻塞业务读写但你拿到的数据是一个时间点的快照不是实时的。这是“一致但不最新”。如果是 MyISAM 表--single-transaction无效MyISAM 不支持事务。为了数据一致必须锁表锁表期间该表不可写严重时会读也被阻塞。我在早期一个系统里遇到的情况是MyISAM 订单表完全没做备份我加锁导出结果线上正好有人在下单直接等了十几秒导致接口超时报警。后来那张表改造为 InnoDB问题解决。检查表引擎SELECT table_name, engine FROM information_schema.tables WHERE table_schemamydb;如果混有 MyISAM 表最好先和处理方沟通或者选业务低谷窗口操作。7. 从手动到定时一个可直接复用的备份脚本讲完原理和踩坑最后聊一下怎么把导出做成自动化。毕竟手动执行 mysqldump 解决不了“天天要备份”的问题。下面这个脚本我长期在用逻辑很简单但很稳定义库名、备份目录、保留天数导出时压缩保留最近 N 天超期的自动删除。#!/bin/bash # mysql_backup.sh DB_HOST127.0.0.1 DB_USERbackup DB_PASSyour_password DB_NAMEmydb BACKUP_DIR/data/mysql_backup KEEP_DAYS7 DATE$(date %Y%m%d_%H%M%S) FILE$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz mkdir -p $BACKUP_DIR mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASS \ --single-transaction --routines --triggers --events \ --databases $DB_NAME | gzip $FILE if [ $? -eq 0 ]; then echo [$(date %F %T)] Backup success: $FILE else echo [$(date %F %T)] Backup failed exit 1 fi find $BACKUP_DIR -type f -name *.sql.gz -mtime $KEEP_DAYS -exec rm -f {} \;有几个细节说明-p$DB_PASS这样写会暴露密码在脚本里所以脚本文件的权限要收紧chmod 700 mysql_backup.sh保证只有 root 能读。更安全的做法是用 MySQL 配置文件.my.cnf存连接参数或者用MYSQL_PWD环境变量但也要注意进程列表会暴露看你的安全要求。--single-transaction这条是脚本的生命线。如果没有它对于 InnoDB 库备份等同于锁表对于线上高并发系统几乎不可接受。定时任务建议加锁避免上次备份还没跑完下一个 cron 又启动了* 2 * * * /usr/bin/flock -n /tmp/mysql_backup.lock /data/mysql_backup.shflock拿不到锁就跳过本次执行保证同一时间只有一个备份任务在跑。有条件的话备份后的文件再往异地传一份最简单的用 rsync 或者 scp 同步到另一台机器。本地存一份、异地存一份双保险。我吃过一次本地磁盘损坏的亏备份文件跟着一起没从那之后异地这份就没断过。8. 导出文件怎么验证导入前的最后一道保险我觉得这是最容易忽略、但也最救命的一步。导出完别急着收工至少花几十秒验证一下。8.1 检查文件完整性# 查看文件大小 ls -lh mydb.sql.gz # 查看压缩包内的 SQL 是否正常 gzip -t mydb.sql.gzgzip -t只能证明压缩包没有损坏不能证明 SQL 内容没问题。8.2 抽样检查关键表如果你导出的是整个库可以在目标环境里先做一次快速导入测试或者至少把文件解压grep 出某张核心表的建表语句和数据条数做个对比grep CREATE TABLE \users\ mydb.sql grep -c INSERT INTO \users\ mydb.sqlINSERT 的数量不等于行数因为一条 INSERT 可能包含多行值但文件里有内容总比没有强。更严格的做法# 解压后用 tail 看文件结尾 gunzip -c mydb.sql.gz | tail -20正常的 mysqldump 导出文件在最后会有-- Dump completed on 2025-01-01 12:00:00看到这行通常说明导出过程完整跑完了。如果没有大概率是中途断掉了或者内存被杀文件不完整。8.3 在隔离环境做一次导入演练条件允许的话我的建议是每次重大变更前在本地用 Docker 起一个临时 MySQL 实例把备份文件导入进去跑几条关键 SQL 验证数据完整性。不用多复杂docker run --name backup_test -e MYSQL_ROOT_PASSWORDtest -d mysql:8.0 docker cp mydb.sql.gz backup_test:/tmp/ docker exec backup_test sh -c gunzip /tmp/mydb.sql.gz | mysql -u root -p test验证完直接删容器不占用任何正式资源。这十分钟的演练能避免你在正式切换环境时发现备份文件有问题而手足无措。9. 踩过的坑完整排查链路实录分享两个我印象最深的真实事故当时排查的过程很值得参考。9.1 SSL 连接错误导出命令直接卡死有一次在一台新部署的 MySQL 8.0 服务器上执行 mysqldump命令刚敲完直接报ERROR 2026 (HY000): SSL connection error: protocol version mismatch首先要说明的是这个报错跟“网络不通”或者“密码错误”是两回事。SSL connection error表示 TCP 连接已经建立了但 MySQL 服务端和客户端的 TLS 握手阶段处理版本不对。排查步骤检查客户端版本和服务端版本。那台服务器上 mysqldump 版本是 8.0.33没问题。检查服务端 SSL 配置。看SHOW VARIABLES LIKE have_ssl和ssl_cert、ssl_ca的路径配置。发现ssl_ca路径指向的 CA 文件不存在。确认问题根源服务端声明了 CA 文件但文件缺失导致 TLS 证书链验证失败客户端认为协议版本不匹配。临时绕过方案在 mysqldump 命令中禁用 SSL--ssl-modeDISABLED。生产环境这不是最终解决但能快速恢复备份。最终修复生成正确的 CA 证书并配置到ssl_ca路径重新加载实例。这类问题在网上搜出来的答案大多是“加--ssl-modeDISABLED绕过”但作为接班的人你最好搞清楚为什么需要绕过。环境里如果有强制 SSL 的合规要求绕过只是暂时保业务长期还是得修证书链路。9.2 导出文件导入后数据错位一次迁移任务导出的 SQL 文件在两个库之间导入逻辑上看一切正常但查询结果对不上。排查发现导出的文件缺了--complete-insert参数而源表字段顺序并不是建表语句里的字段顺序以前做过 ALTER TABLE 变更导致部分行的字段顺序对了、但值插入错位。mysqldump 默认生成的 INSERT 语句是INSERT INTO t VALUES (1, a, b);如果目标表的字段顺序和源表不完全一致这种写法就是灾难。加上--complete-insert之后INSERT INTO t (id, col_a, col_b) VALUES (1, a, b);字段名写清楚了顺序错不了的。从那以后凡是要跨环境导入的导出我默认都会加上--complete-insert。这算是一个用事故换来的经验。10. 如果你用的是 MySQL 8.0几个必须了解和适配的变化MySQL 8.0 在权限和默认参数上跟 5.7 相比变化很大导出实操中有些东西需要重新适应。密码认证插件。MySQL 8.0 默认认证插件是caching_sha2_password而 5.7 时代大量驱动和客户端工具用的是mysql_native_password。如果你从 8.0 导出文件导入回 5.7或者反过来很可能遇到认证失败。处理方案是迁移前确认两端认证插件SELECT user, host, plugin FROM mysql.user WHERE userbackup;如果两端插件不一致可以在 8.0 端把用户调整为旧插件不推荐长期用或者更新客户端连接到新版。GTID 的影响。MySQL 8.0 中 GTID 默认开启。导出时如果不加--set-gtid-purgedOFF导出文件里会包含SET GLOBAL.GTID_PURGED...。导入时如果目标库的 GTID 状态不允许会直接报错。从 MySQL 8.0 导出、目标库接 5.7 或者 GTID 配置不一致时注意手动指定mysqldump -u root -p --set-gtid-purgedOFF mydb mydb.sql我自己在 8.0 到 8.0 的迁移里大部分情况反而需要保留 GTID 信息只要目标实例是全新的、没有历史 GTID导入没问题。先确认好源和目标的状态再决定参数。默认字符集已经是 utf8mb4。8.0 的默认字符集是utf8mb4导出时即使不指定字符集文件本身也基本不会乱码。但如果你要导入的目标是 5.7 实例而那个实例默认字符集是latin1导入时必须显式指定字符集否则表内数据按目标库默认字符集解释中文照样乱码。sql_mode 变化。8.0 的默认sql_mode更严格比如包含ONLY_FULL_GROUP_BY和STRICT_TRANS_TABLES。导出的 SQL 文件如果包含以前宽松模式下的 SQL 写法导入到 8.0 有可能因为严格模式而报错。遇到这种情况可以在导入会话中调整mysql -u root -p --init-commandSET SESSION sql_mode mydb mydb.sql注意这是临时措施正式环境应该修改 SQL 语法本身但迁移过程中快速通过这招有用。11. 最后分享三点长期有用的习惯以上是导出导入的完整链路。结合这么多年反复踩坑的经验最后沉淀几句给你。第一导出数据库从来不是“跑一条命令”这么简单你要搞清楚导出的内容、格式、字符集、权限、是否阻塞业务这五个维度全对了导出文件才算合格。第二备份文件永远不要把鸡蛋放在一个篮子里。本地磁盘一份、异地一份、定期做恢复演练。备份做了三年没人验证过某天真要恢复时发现备份文件根本导不进去那比没备份更伤人。我最感谢自己的一次决策就是坚持每月在 Docker 里做一次完整导入演练。第三命令别靠背要靠理解。mysqldump的参数组合不过二十来个花半天时间把官方文档对应的每一条过一遍远比每次出问题搜答案更划算。尤其是--single-transaction、--routines、--triggers、--complete-insert、--set-gtid-purged这几个理解它们背后的机制你就能覆盖 90% 以上的导出需求。如果看完这篇文章你只能记住一个动作我希望是下次导完数据库先解压看一眼文件结尾有没有 “Dump completed on”再做其他操作。
阅读完成 · 觉得有帮助?