scp传输失败主因是权限、路径或网络问题,需检查sshd状态、防火墙、私钥权限600、用绝对路径、目标目录写权限;rsync更稳但须注意斜杠和--delete风险;脚本中易漏dump成功校验、压缩传输及旧备份清理。

备份文件生成后,scp 传不过去的常见原因
MySQL 备份本身不负责传输,mysqldump 或 mysqlpump 输出的是本地文件,得靠系统工具推过去。传失败通常不是 MySQL 的问题,而是权限、路径或网络策略卡住。
常见错误现象:Permission denied (publickey)、No such file or directory、Connection timed out。
- 确认目标机器
sshd正在运行,且防火墙放行了 22 端口(ufw status或iptables -L) - 本地私钥权限必须是
600(chmod 600 ~/.ssh/id_rsa),否则 ssh 拒绝加载 - 目标路径写全:用绝对路径,比如
/backup/mysql/20240512.sql,别用~/backup/—— scp 不展开波浪号 - 如果目标用户不是 root,确保该用户对目标目录有写权限(
chown -R backupuser:backupuser /backup/mysql)
rsync 同步比 scp 更稳,但得注意 --delete 和路径斜杠
rsync 适合增量同步或定时任务,但一个斜杠差就能删错目录。它默认不递归同步单个文件,容易误以为“没传成功”。
使用场景:每天凌晨 dump 后只传新增/变更部分;需要保留历史多个备份版本;带宽有限需压缩传输。
- 同步单个文件:末尾不加
/,例如rsync -avz backup.sql user@host:/backup/ - 同步整个目录:源路径末尾加
/,否则会把目录本身也建进去(rsync -avz /backup/ user@host:/backup/) - 慎用
--delete:它会让目标严格匹配源,如果源目录临时为空或路径写错,目标备份可能被清空 - 加
-e "ssh -p 2222"指定非标端口,避免因端口不对连都连不上
备份 + 传输脚本里最容易漏的三件事
写个 backup.sh 把 mysqldump 和 scp 串起来很常见,但线上出问题往往就在这几步。
- 没检查
mysqldump是否真成功:加|| exit 1,否则 dump 失败了还继续传空文件 - 没压缩再传:大库直接传
.sql效率低,用gzip -c backup.sql | ssh user@host "gunzip > /backup/backup.sql"更省带宽 - 没清理旧备份:本地留 7 天、远程留 30 天是常见做法,但
find /backup -name "*.sql" -mtime +30 -delete要测试好路径,别写成/ * .sql
MySQL 8.0+ 使用 mysqlpump 时,输出格式影响传输后恢复
mysqlpump 默认并行导出、带 CREATE DATABASE 和注释,但恢复时如果目标库已存在,会报 ERROR 1007 (HY000): Can't create database 'xxx'; database exists。
这不是传输问题,但常被误认为“文件传坏了”。关键是导出参数和恢复命令要配对。
- 导出时加
--skip-definer --exclude-databases=sys,information_schema,performance_schema,减少权限和系统库干扰 - 若目标环境无对应用户,加
--users会导出CREATE USER,但恢复时需有CREATE USER权限,否则报错 - 传到远程后,别直接
mysql ,先用 <code>head -20 backup.sql看前几行有没有CREATE DATABASE,再决定是否手动CREATE DATABASE IF NOT EXISTS xxx
传输只是搬运工,真正让备份可用的,是 dump 参数、目标环境一致性、以及每一步是否真的执行成功 —— 日志里那行 “completed OK” 得亲眼看见才算数。











