关键在于准确判断失败(用$?或${pipestatus[0]})、保留stderr错误日志、告警带主机名、时间、mysql版本、磁盘空间及脱敏后最近5行错误内容。

捕获 MySQL 执行异常并报警,关键不是“有没有报错”,而是“有没有真正识别到失败”——很多脚本看似在跑,其实失败了却无声无息。核心在于三点:准确判断失败、保留失败证据、带上下文告警。
用 $? 判断真实退出状态,别信文件大小或 --force
mysqldump、mysql 命令成功返回 0,失败返回非 0(如 2=连接失败、3=权限不足、4=表不存在)。这是唯一可信依据。
- 删掉所有 --force 参数:它会让 mysqldump 忽略错误继续执行,生成空 SQL 却返回 0
- 别用 ls -l backup.sql | awk '{print $5}' 判断是否成功——gzip 压缩后空文件也有 20+ 字节
- 验证 SQL 文件是否真有内容:head -c 1 backup.sql | wc -c,结果为 0 才说明首字节不可读
- 若用了管道压缩(如 mysqldump | gzip),必须用 ${PIPESTATUS[0]} 捕获 mysqldump 真实退出码
stderr 不能丢,至少临时保存供分析
重定向 2>/dev/null 是静默失败的主因。关键错误(如 Access denied、Can't connect)都走 stderr。
- 把 stderr 重定向到临时文件:2> /tmp/mysql_err.$$.log
- 告警时附上最近 5 行脱敏内容:tail -5 /tmp/mysql_err.$$.log | sed 's/password=[^ ]*//g'
- 执行完立即检查:if [ ${PIPESTATUS[0]} -ne 0 ]; then ...
告警内容必须含可定位信息,不写“失败”两个字
运维半夜被叫醒,需要的是立刻动手的线索,不是模糊提示。
- 必含字段:主机名($(hostname))、时间($(date))、MySQL 版本(mysql --version)
- 磁盘空间:当前 /backup 分区剩余容量(df -h /backup | awk 'NR==2 {print $4}')
- 错误日志路径确认:mysql -e "SHOW VARIABLES LIKE 'log_error';" 2>/dev/null
- 用 /bin/mailx 发送(比 mail/mutt 更稳定),发送前校验存在:which mailx >/dev/null || exit 1
连不上、权限拒、日志爆满,三类高频异常要单独盯
日常最常卡住的不是语法错,而是环境级问题:
- 连接失败:用 mysqladmin ping -u root -p'xxx' --silent &>/dev/null 快速探测,超时即告警
- 权限拒绝:扫描错误日志中 "Access denied for user" 条目,10 分钟内超 5 次就触发(防暴力破解)
- 磁盘写满:备份前先查 df -h /var/lib/mysql /backup,任一低于 10% 就中止并告警











