迁移网站、恢复备份或克隆测试环境,归根结底都是两个操作:把数据库导出为文件,再把它导入回去。在 VPS Linux Infrawire 上,只需几条命令即可完成,无需任何网页界面。本指南涵盖一致性导出、压缩、大文件处理、字符编码以及服务器之间的直接传输。
📋 前提条件
- 一台运行 Ubuntu 24.04 或 Debian 12 的 Linux VPS,并拥有 root SSH 权限(IP 地址和 root 密码可在您的客户区找到)
- 已安装 MySQL 或 MariaDB,至少要有客户端(
apt install mariadb-client) - 一个对待导出数据库拥有
SELECT、SHOW VIEW、TRIGGER、LOCK TABLES和EVENT权限的数据库用户 - 足够的剩余磁盘空间:用
df -h检查
1. 使用 mysqldump 导出数据库
对于 InnoDB 表(默认引擎),--single-transaction 会在不锁表的情况下生成一致的快照,因此导出期间网站可继续运行。
Bashmysqldump -u USER -p --single-transaction --quick DBNAME > DBNAME.sql
在较新的 MariaDB 版本中,该工具也以 mariadb-dump 的名称提供,选项完全相同。
2. 包含存储过程、触发器和事件
触发器默认会被导出,但存储过程、函数和计划事件必须显式指定。指定字符集可以避免中文和表情符号出现乱码。
Bashmysqldump -u USER -p --single-transaction --routines --triggers --events \ --default-character-set=utf8mb4 DBNAME > DBNAME.sql
常用变体:
Bash# 仅导出结构,不含数据行 mysqldump -u USER -p --no-data DBNAME > schema.sql # 导出多个数据库,并包含 CREATE DATABASE 语句 mysqldump -u USER -p --single-transaction --databases DB1 DB2 > two-dbs.sql # 导出服务器上的所有数据库 mysqldump -u root -p --single-transaction --routines --events --all-databases > all.sql
3. 使用 gzip 压缩导出文件
SQL 文本的压缩率很高。把输出直接通过管道交给 gzip,未压缩的文件就不会落到磁盘上。
Bashmysqldump -u USER -p --single-transaction --routines --events DBNAME | gzip > DBNAME_$(date +%F).sql.gz
为了不必每次输入密码(也避免它出现在 ps 输出中),可将其保存到 ~/.my.cnf:
INI[client] user=USER password=YOUR_PASSWORD
Bashchmod 600 ~/.my.cnf
4. 导入数据库
先用现代字符集创建目标数据库,然后再加载文件。
Bashmysql -u USER -p -e 'CREATE DATABASE IF NOT EXISTS DBNAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;' mysql -u USER -p --default-character-set=utf8mb4 DBNAME < DBNAME.sql # 从压缩文件导入 gunzip -c DBNAME.sql.gz | mysql -u USER -p --default-character-set=utf8mb4 DBNAME
警告: 导出文件默认包含 DROP TABLE IF EXISTS,导入到已有数据库会替换同名的表。请先备份目标数据库。
5. 处理大文件
对于数 GB 的导出文件,请在 tmux 中运行导入,这样 SSH 断开也不会中断任务,并用 pv 查看进度。
Bashapt install -y tmux pv tmux new -s import pv DBNAME.sql.gz | gunzip | mysql -u USER -p --max-allowed-packet=512M DBNAME
按 Ctrl+B 再按 D 脱离会话,稍后用 tmux attach -t import 重新连接。
6. 通过 SSH 直接传输到另一台服务器
无需中间文件:数据经加密的 SSH 管道传输,到达后立即导入。两端的凭据均从 ~/.my.cnf 读取(root 用户也可使用本地 socket)。
Bashmysqldump --single-transaction --routines --events DBNAME | gzip \ | ssh root@NEW_VPS_IP 'gunzip | mysql DBNAME'
目标服务器上必须已存在数据库 DBNAME。
✅ 验证结果
Bashgzip -t DBNAME.sql.gz && echo 'archive OK' mysql -e 'SHOW TABLES;' DBNAME mysql -e 'SELECT COUNT(*) FROM TABLENAME;' DBNAME mysql -e "SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name='DBNAME';"
对比源端和目标端几张关键表的行数。
🔧 故障排查
ERROR 1045 Access denied:用户名或密码错误,或该用户不允许从此主机连接。请先用 mysql -u USER -p 测试。
ERROR 2006 MySQL server has gone away:某一行或查询超出了 max_allowed_packet。在服务器配置的 [mysqld] 段中调大该值并重启服务,或给客户端加上 --max-allowed-packet=512M。
导入后中文乱码:文件被以错误的字符集读取。导出时使用 --default-character-set=utf8mb4,导入时也使用同一选项。
ERROR 1227 或 DEFINER 错误:导出文件引用了目标服务器上不存在的用户。导入时去掉该子句:
Bashsed -E 's/DEFINER=`[^`]+`@`[^`]+`//g' DBNAME.sql | mysql -u USER -p DBNAME
🎉 现在,您的数据库可以轻松备份、恢复并在服务器之间迁移了!