不是必须,但对innodb表几乎必须;不加会导致flush tables with read lock阻塞写入,加了才能通过mvcc快照实现无锁一致备份,且仅对innodb有效。

MySQL 备份命令必须加 --single-transaction 吗?
不是必须,但对 InnoDB 表几乎必须。不加的话,mysqldump 默认会执行 FLUSH TABLES WITH READ LOCK,导致写操作阻塞——线上服务一卡就是几分钟。加了 --single-transaction 才能利用 MVCC 实现无锁一致备份。
注意:该参数仅对 InnoDB 有效;如果库中混有 MyISAM 表,仍需配合 --lock-tables=false(否则报错),但此时 MyISAM 部分不保证一致性——建议统一用 InnoDB。
- 必加项:
--single-transaction --routines --triggers --events - 避免密码明文:
--defaults-extra-file=/etc/mysql/backup.cnf,该文件权限必须是600,内容只含[client]段和user/password - 压缩可选但推荐:
| gzip > backup.sql.gz,节省空间且传输更快
Shell 脚本里怎么安全处理日期命名和保留策略?
用 date 命令生成文件名时,别直接写 $(date +%Y%m%d)——万一脚本跨天运行(比如凌晨 23:59 开始、00:01 结束),备份文件名和实际时间对不上,归档逻辑会乱。
正确做法:在脚本开头就固定一个时间戳变量,后续所有路径、文件名、日志都基于它。
BACKUP_TIME=$(date -d 'today' +'%Y%m%d_%H%M%S')
BACKUP_FILE="full_${BACKUP_TIME}.sql.gz"
DST_DIR="/backup/mysql/${BACKUP_TIME:0:4}/${BACKUP_TIME:4:2}"
保留策略建议用 find 而非 rm -rf 直删:
- 保留最近 7 天本地备份:
find /backup/mysql -name "full_*.sql.gz" -mtime +7 -delete - 注意
-mtime +7表示“修改时间超过 7×24 小时”,不是“7 天前”——更准 - 异地归档前先
test -f $BACKUP_FILE && scp $BACKUP_FILE user@archive-host:/archive/mysql/,避免空文件误传
scp 传到异地服务器失败,常见原因有哪些?
不是网络不通就是权限问题。优先排查这三项:
- 目标机器的
/archive/mysql/目录存在且user有写权限(chown user:user /archive/mysql) - 脚本里用的是免密登录,但
ssh-agent在 cron 环境下默认不生效——改用ssh-add或直接指定 key:scp -i /root/.ssh/backup_id_rsa $BACKUP_FILE ... - 目标主机的
sshd_config是否禁用了PermitEmptyPasswords no和PasswordAuthentication no(应该关);但若用密码登录,则 cron 下无法交互输入——只能换密钥
加个简单检测:在 scp 前跑一句 ssh -o ConnectTimeout=5 -o BatchMode=yes user@archive-host 'echo ok' 2>/dev/null,返回非 0 就跳过上传并记日志。
cron 执行备份脚本总失败,但手动运行却正常?
环境变量是最大坑。cron 使用最小 shell 环境,$PATH 通常只有 /usr/bin:/bin,找不到 mysqldump(常在 /usr/local/mysql/bin)或 gzip(某些系统在 /usr/sbin)。
解决方法只有两个,二选一:
- 在脚本开头显式声明 PATH:
export PATH="/usr/local/mysql/bin:/usr/local/bin:/usr/bin:/bin" - 所有命令写绝对路径:
/usr/local/mysql/bin/mysqldump、/bin/gzip、/usr/bin/scp
另外,cron 的 $HOME 是 root(或对应用户)目录,~/.my.cnf 可能读不到——坚持用 --defaults-extra-file 指定完整路径,别依赖 home 目录。
异地归档真正麻烦的从来不是脚本本身,而是时间戳对齐、权限继承和 cron 环境隔离这三个点。漏掉任意一个,备份就变成“看起来在跑,其实没存”。











