Linux下MySQL数据库故障系统化诊断的脚本分享

 更新时间:2026年07月13日 09:28:39   作者:weixin_30777913  
文章浏览阅读198次,点赞7次,收藏3次,【代码】Linux下MySQL数据库故障系统化诊断脚本,

前言

MySQL 意外中断后的系统化诊断脚本,融合四大哲学元原则:

1. 本体论 - 区分现象与本质,不盲从表面状态

2. 整体论 - 建立多维度时间关联,定位涌现的因果链

3. 辩证法 - 为恢复方案提供明确的权衡维度

4. 无为/奥卡姆 - 引导配置精简与自愈约束

核心增强特性

1. 每段代码【单段可复制终端执行】,分段粘贴即可独立采集信息

2. 所有PID/日志路径/数据目录红色高亮,统一存入可复制清单文件

3. 同时兼容宿主机systemd MySQL & Docker容器MySQL

4. 自动生成预填充路径/PID的一键修复命令,复制直接运行

使用:   bash mysql_crash_diag.sh [输出目录]

(建议以 root / sudo 执行,完整采集内核、服务、权限信息)

脚本代码

#!/bin/bash
#===============================================================================
# 脚本名称: mysql_crash_diag.sh
# 
#===============================================================================
set -o pipefail
# -----------------------------【单段可复制终端执行】全局常量、颜色、工具函数 -----------------------------
# 入参与时间戳
OUT_DIR="${1:-/tmp/mysql_diag_$(date +%Y%m%d_%H%M%S)}"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
mkdir -p "$OUT_DIR"
# 统一存放所有可复制关键路径、PID、故障标记
KEY_COPY_FILE="${OUT_DIR}/key_copy_info.txt"
> "$KEY_COPY_FILE"
echo "===== 全部可复制关键信息汇总(PID/日志/配置/数据目录) =====" > "$KEY_COPY_FILE"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
WHITE='\033[1;37m'
CYAN='\033[0;36m'
NC='\033[0m'
# 日志打印函数
info() { echo -e "${GREEN}[INFO]${NC} $*"; echo "[正常] $*" >> "$KEY_COPY_FILE"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; echo "[警告] $*" >> "$KEY_COPY_FILE"; }
err()  { echo -e "${RED}[ERROR]${NC} $*"; echo "[严重异常] $*" >> "$KEY_COPY_FILE"; }
section() { echo -e "\n${YELLOW}========== $1 ==========${NC}"; echo -e "\n【诊断模块】$1" >> "$KEY_COPY_FILE"; }
# 核心:打印高亮可复制变量,自动写入清单
print_copy() {
    local label="$1"
    local val="$2"
    echo -e "${WHITE}【可复制 $label 】: ${RED}$val${NC}"
    echo "$label = $val" >> "$KEY_COPY_FILE"
}
# 输出可直接执行的完整命令
print_cmd() {
    echo -e "${CYAN}[一键执行命令]${NC} $1"
    echo "执行命令:$1" >> "$KEY_COPY_FILE"
}
# MySQL 全局路径池
MYSQL_LOG_PATHS=( "/var/log/mysqld.log" "/var/log/mysql/error.log" "/var/lib/mysql/*.err" )
MYSQL_CNF_PATHS=( "/etc/my.cnf" "/etc/mysql/my.cnf" "/usr/local/mysql/my.cnf" )
MYSQL_DATA_PATHS=( "/var/lib/mysql" "/usr/local/mysql/data" )
# 全局缓存变量(全程复用,所有命令自动带入)
MYSQL_PID=""
FOUND_ERR_LOG=""
SELECTED_CNF=""
DATA_DIR=""
CRASH_TIMESTAMP=""
IS_DOCKER_MYSQL=0
DOCKER_MYSQL_CID=""
# ----------------------------------------------------------------------------------------------------------
# -----------------------------【单段可复制终端执行】0. 部署模式自动识别:宿主机 / Docker MySQL -----------------------------
section "0. 识别MySQL部署模式(宿主机systemd / Docker容器)"
# 先判断宿主机本地MySQL进程
MYSQL_PID=$(pgrep -x mysqld | head -1 || pgrep -x mariadbd | head -1)
if [[ -n "$MYSQL_PID" ]]; then
    info "检测到宿主机本地MySQL进程,PID已缓存"
    print_copy "MySQL主进程PID" "$MYSQL_PID"
    # 自动解析数据目录
    DATA_DIR=$(ps -ef | grep mysqld | grep -oP '--datadir=\K\S+' | head -1)
    [[ -z "$DATA_DIR" ]] && DATA_DIR="/var/lib/mysql"
    print_copy "MySQL数据目录" "$DATA_DIR"
else
    # 无本地进程,检查Docker内MySQL容器
    DOCKER_MYSQL_CID=$(docker ps -a --filter "name=mysql" --filter "name=mariadb" -q | head -1 2>/dev/null || true)
    if [[ -n "$DOCKER_MYSQL_CID" ]]; then
        IS_DOCKER_MYSQL=1
        warn "未检测到宿主机MySQL,识别到Docker MySQL容器"
        print_copy "Docker MySQL容器CID" "$DOCKER_MYSQL_CID"
        print_cmd "docker logs $DOCKER_MYSQL_CID --tail 300"
        print_cmd "docker exec -it $DOCKER_MYSQL_CID cat \$(mysql -sse \"SELECT @@log_error;\")"
    else
        warn "未找到宿主机MySQL进程、无MySQL容器,请手动确认部署方式"
        print_cmd "ps aux | grep -E mysqld|mariadb"
        print_cmd "docker ps -a | grep -E mysql|mariadb"
    fi
fi
echo "[$TIMESTAMP] 诊断报告生成中,全部数据存放目录: $OUT_DIR" | tee "$OUT_DIR/report.log"
print_copy "诊断文件根目录" "$OUT_DIR"
print_cmd "cat $KEY_COPY_FILE # 查看所有可复制PID、路径汇总"
# ==========================================================================================================
# 步骤1:现象取证与时间锚定(本体论 & 整体论)【单段可复制终端执行】
# ==========================================================================================================
section "1. 现象取证,保护现场快照(内核/服务/进程)"
# 1.1 内核环形缓冲(OOM、硬件IO崩溃底层根源)
dmesg > "$OUT_DIR/dmesg_full.log" 2>/dev/null || echo "无法保存dmesg,手工执行: dmesg > dmesg_manual.log" | tee -a "$OUT_DIR/report.log"
# 单独提取OOM与磁盘错误,单独存档
grep -i "oom-killer\|killed process\|i/o error\|ro filesystem" "$OUT_DIR/dmesg_full.log" > "$OUT_DIR/dmesg_oom_io_err.log"
info "内核OOM/IO错误快照保存: $OUT_DIR/dmesg_oom_io_err.log"
# 1.2 systemd服务状态快照(宿主机模式)
if [[ $IS_DOCKER_MYSQL -eq 0 ]]; then
    if command -v systemctl &>/dev/null; then
        systemctl status mysqld 2>/dev/null > "$OUT_DIR/mysqld_systemd.log" || systemctl status mariadb > "$OUT_DIR/mysqld_systemd.log" 2>/dev/null
        journalctl -u mysqld --since "10 min ago" --no-pager > "$OUT_DIR/mysqld_journal.log" 2>/dev/null
    else
        service mysql status > "$OUT_DIR/mysqld_service.log" 2>/dev/null
    fi
else
    # Docker模式:抓取容器启停日志
    docker logs "$DOCKER_MYSQL_CID" --tail 500 > "$OUT_DIR/docker_mysql_container_log.log" 2>/dev/null
fi
# 1.3 全量进程快照
ps aux > "$OUT_DIR/all_process_snapshot.log"
ps aux | grep -v grep | grep -E mysqld|mariadb > "$OUT_DIR/mysql_process.log"
info "MySQL进程快照已保存"
# 1.4 端口占用检查(常见启动失败原因)
ss -tlnp | grep 3306 > "$OUT_DIR/port_3306_occupy.log"
if [[ -s "$OUT_DIR/port_3306_occupy.log" ]]; then
    warn "检测到3306端口占用,查看文件确认占用进程"
    cat "$OUT_DIR/port_3306_occupy.log"
fi
# 1.5 自动提取崩溃时间戳(因果链锚点)
CRASH_TIMESTAMP=""
# 从systemd日志提取停机时间
if [[ -f "$OUT_DIR/mysqld_systemd.log" ]]; then
    CRASH_TIMESTAMP=$(grep -i "Active: inactive\|stop\|failed" "$OUT_DIR/mysqld_systemd.log" | head -1 | grep -oP '\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')
fi
# 内核OOM时间兜底
if [[ -z "$CRASH_TIMESTAMP" && -s "$OUT_DIR/dmesg_oom_io_err.log" ]]; then
    CRASH_TIMESTAMP=$(grep -i "mysql\|mariadb" "$OUT_DIR/dmesg_oom_io_err.log" | tail -1 | grep -oP '\[\s*\d+\.\d+\]' | head -1)
fi
print_copy "推断崩溃关键时间戳" "${CRASH_TIMESTAMP:-未识别,请人工核对日志时间}"
echo "推断的关键异常时间点: ${CRASH_TIMESTAMP:-未自动识别,请手工检查日志时间戳}" | tee -a "$OUT_DIR/report.log"
# 手工检验可复制命令
print_cmd "ls -lt /var/log/mysqld.log /var/log/messages"
print_cmd "journalctl -u mysqld --since \"$CRASH_TIMESTAMP\" --no-pager"
# ==========================================================================================================
# 步骤2:直达本质——错误日志本体分析【单段可复制终端执行】
# ==========================================================================================================
section "2. 扫描MySQL错误日志,提取底层崩溃根源"
# 自动检索真实错误日志路径
for LOG in "${MYSQL_LOG_PATHS[@]}"; do
    for F in $LOG; do
        if [ -f "$F" ]; then
            FOUND_ERR_LOG="$F"
            break 2
        fi
    done
done
# Docker模式特殊读取容器内日志
if [[ $IS_DOCKER_MYSQL -eq 1 && -z "$FOUND_ERR_LOG" ]]; then
    warn "宿主机未找到日志,从Docker容器内抓取错误日志"
    docker exec "$DOCKER_MYSQL_CID" bash -c "cat \$(mysql -sse \"SELECT @@log_error;\")" > "$OUT_DIR/mysqld_error.log" 2>/dev/null
    FOUND_ERR_LOG="$OUT_DIR/mysqld_error.log"
fi
if [ -z "$FOUND_ERR_LOG" ]; then
    err "未找到MySQL错误日志,请手动指定日志路径"
    print_cmd "find / -name \"*.err\" 2>/dev/null"
else
    cp "$FOUND_ERR_LOG" "$OUT_DIR/mysqld_error.log"
    print_copy "MySQL错误日志完整路径" "$FOUND_ERR_LOG"
    echo "错误日志源文件: $FOUND_ERR_LOG" | tee -a "$OUT_DIR/report.log"
    # 提取致命错误、崩溃标记
    echo "--- 最近致命错误、崩溃警告 ---" >> "$OUT_DIR/report.log"
    grep -iE "error|fatal|assert|corrupt|tablespace|disk full|oom|signal 11|signal 9|permission denied" "$OUT_DIR/mysqld_error.log" | tail -30 | tee -a "$OUT_DIR/report.log"
fi
# 本体论分层分析注释(保留原有哲学逻辑)
# 1. Disk is full → 磁盘耗尽,优先清理binlog
# 2. InnoDB tablespace corrupted → 存储介质损坏,逐级innodb_force_recovery导出数据
# 3. OOM / out of memory → 进程被系统强制杀死,非程序主动退出
# 4. Too many open files → ulimit与my.cnf文件句柄配置不匹配
# 5. Signal 11(SIGSEGV) / Signal6(ABRT) → 内存越界/数据库内部断言崩溃
# ==========================================================================================================
# 步骤3:整体论关联——多维时间点交叉验证OOM/IO突变【单段可复制终端执行】
# ==========================================================================================================
section "3. 整体论交叉校验:OOM内存耗尽 / 磁盘IO硬件故障"
# 提取内核OOM、IO报错
DMESG_OOM=$(cat "$OUT_DIR/dmesg_oom_io_err.log" | grep -i "out of memory\|oom-killer" | tail -5)
DMESG_IO=$(cat "$OUT_DIR/dmesg_oom_io_err.log" | grep -i "i/o error\|read-only\|filesystem error\|blk dev" | tail -5)
# OOM内存耗尽链路校验
if [ -n "$DMESG_OOM" ]; then
    warn "【辩证矛盾点】检测到OOM Killer杀死进程,优先核对内存参数,而非单纯加内存"
    echo "$DMESG_OOM" | tee -a "$OUT_DIR/report.log"
    echo "--- 当前宿主机内存/swap快照 ---" >> "$OUT_DIR/report.log"
    free -h >> "$OUT_DIR/report.log"
    # 历史内存回溯(sysstat sar)
    if command -v sar &>/dev/null; then
        echo "--- 近1小时内存历史曲线 ---" >> "$OUT_DIR/report.log"
        sar -r -f /var/log/sa/sa$(date +%d) 2>/dev/null | grep -E "^[0-9]" | tail -12 >> "$OUT_DIR/report.log" || echo "当日sar数据不存在" >> "$OUT_DIR/report.log"
    else
        warn "未安装sysstat,无历史内存数据,手工命令:sar -r 1 10"
    fi
    print_cmd "grep innodb_buffer_pool_size $SELECTED_CNF"
fi
# IO/只读文件系统链路校验
if [ -n "$DMESG_IO" ]; then
    warn "【辩证矛盾点】磁盘IO异常/文件系统只读,会直接导致MySQL崩溃、写失败"
    echo "$DMESG_IO" | tee -a "$OUT_DIR/report.log"
    echo "--- 当前挂载列表,检查ro只读标记 ---" >> "$OUT_DIR/report.log"
    mount | grep -E "$DATA_DIR|/ " >> "$OUT_DIR/report.log"
    print_cmd "mount -o remount,rw $DATA_DIR挂载盘"
    print_cmd "fsck -n /dev/磁盘设备 # 停机后磁盘校验"
fi
# 整体论核心逻辑:对齐dmesg、错误日志、sar三者时间戳,识别连锁故障
# 示例因果链:内存耗尽OOM kill mysqld → 大量事务回滚 → binlog持续膨胀 → 磁盘100%占满
# 单一日志无法识别完整因果,必须多维度时间交叉比对
# ==========================================================================================================
# 步骤4:奥卡姆剃刀资源限制检查(磁盘、inode、文件句柄、binlog)【单段可复制终端执行】
# ==========================================================================================================
section "4. 资源硬限制排查:磁盘空间、inode、文件句柄、binlog堆积"
echo "--- 全局磁盘使用率(系统盘+MySQL数据盘+临时目录) ---" >> "$OUT_DIR/report.log"
df -h / "$DATA_DIR" /tmp 2>/dev/null | tee -a "$OUT_DIR/report.log"
echo "--- inode耗尽检查(小文件过多隐形崩溃) ---" >> "$OUT_DIR/report.log"
df -i / "$DATA_DIR" /tmp 2>/dev/null | tee -a "$OUT_DIR/report.log"
# binlog堆积检测(磁盘占满头号诱因)
if [ -d "$DATA_DIR" ]; then
    BINLOG_SIZE=$(du -sh "$DATA_DIR/mysql-bin."* 2>/dev/null | head -1)
    [ -n "$BINLOG_SIZE" ] && print_copy "Binlog总占用大小" "$BINLOG_SIZE" && echo "Binlog文件占用: $BINLOG_SIZE" | tee -a "$OUT_DIR/report.log"
fi
# 错误日志膨胀检查
if [ -f "$FOUND_ERR_LOG" ]; then
    ERR_LOG_SIZE=$(du -sh "$FOUND_ERR_LOG" 2>/dev/null | awk '{print $1}')
    print_copy "错误日志文件大小" "$ERR_LOG_SIZE"
    echo "错误日志大小: $ERR_LOG_SIZE (GB级日志需配置logrotate自动切割)" | tee -a "$OUT_DIR/report.log"
fi
# 文件句柄限制(too many open files崩溃根源)
echo "--- MySQL进程文件句柄硬限制 ---" >> "$OUT_DIR/report.log"
if [ -n "$MYSQL_PID" ]; then
    cat "/proc/$MYSQL_PID/limits" | grep "open files" | tee -a "$OUT_DIR/report.log"
    print_cmd "lsof -p $MYSQL_PID | wc -l # 统计当前打开文件总数"
else
    warn "无运行MySQL进程,无法读取进程级fd限制"
fi
echo "系统全局open file限制: $(ulimit -n)" >> "$OUT_DIR/report.log"
print_cmd "grep open_files_limit $SELECTED_CNF"
# 奥卡姆剃刀无为优化思路:
# 1. 配置binlog_expire_logs_seconds自动清理binlog,避免人工频繁清理
# 2. logrotate自动切割错误日志,防止日志无限膨胀占满磁盘
# 3. 统一调高系统与MySQL两层open_files_limit,消除句柄瓶颈
# ==========================================================================================================
# 步骤5:配置参数本体审查(内存、InnoDB核心参数校验)【单段可复制终端执行】
# ==========================================================================================================
section "5. MySQL核心配置文件审查,高危参数风险校验"
# 自动检索配置文件
for CNF in "${MYSQL_CNF_PATHS[@]}"; do
    if [ -f "$CNF" ]; then
        SELECTED_CNF="$CNF"
        cp "$CNF" "$OUT_DIR/my.cnf_backup"
        break
    fi
done
if [ -f "$SELECTED_CNF" ]; then
    print_copy "MySQL配置文件路径" "$SELECTED_CNF"
    echo "从 $SELECTED_CNF 提取风险核心参数:" | tee -a "$OUT_DIR/report.log"
    grep -E "innodb_buffer_pool_size|innodb_log_file_size|innodb_flush_log_at_trx_commit|max_connections|open_files_limit|binlog_expire|expire_logs_days|core-file" "$SELECTED_CNF" | tee -a "$OUT_DIR/report.log"
    # 本体论风险校验:buffer_pool超过物理内存70%极易触发OOM
    TOTAL_MEM=$(free -b | awk '/Mem:/ {print $2}')
    BUFF_POOL_RAW=$(grep innodb_buffer_pool_size "$SELECTED_CNF" | grep -oP '\d+' | head -1)
    if [ -n "$TOTAL_MEM" ] && [ -n "$BUFF_POOL_RAW" ]; then
        if [ "$BUFF_POOL_RAW" -gt $((TOTAL_MEM * 70 / 100)) ]; then
            err "高危风险:innodb_buffer_pool_size 超过物理内存70%,OOM崩溃概率极高,建议下调" | tee -a "$OUT_DIR/report.log"
        fi
    fi
else
    warn "未找到my.cnf配置文件,请手动查找配置"
    print_cmd "find /etc /usr/local -name my.cnf 2>/dev/null"
fi
# 补充SELinux权限校验(容器/宿主机通用权限崩溃根源)
section "5.1 SELinux权限审计(permission denied崩溃排查)"
ausearch -m avc -ts recent | grep -E mysql|mariadb > "$OUT_DIR/selinux_avc.log" 2>/dev/null
if [[ -s "$OUT_DIR/selinux_avc.log" ]]; then
    warn "检测到SELinux拦截MySQL文件读写,会导致启动失败/写入崩溃"
    cat "$OUT_DIR/selinux_avc.log"
    print_cmd "chcon -R -t mysqld_db_t $DATA_DIR"
    print_cmd "setsebool -P mysqld_disable_trans 1"
fi
# ==========================================================================================================
# 步骤6:辩证法恢复方案、无为长期预防、一键可复制修复命令【单段可复制终端执行】
# ==========================================================================================================
section "6. 辩证恢复决策清单 + 长期无为预防方案"
echo "===== 故障根因匹配恢复操作(全部命令预填充路径/PID,直接复制运行) =====" | tee -a "$OUT_DIR/report.log"
# 分场景自动匹配修复命令
if grep -qi "out of memory\|oom-killer" "$OUT_DIR/dmesg_oom_io_err.log"; then
    echo -e "\n【场景1:OOM内存耗尽被系统杀死】" | tee -a "$OUT_DIR/report.log"
    print_cmd "sed -i 's/innodb_buffer_pool_size=.*/innodb_buffer_pool_size=4G/' $SELECTED_CNF # 根据物理内存调整"
    print_cmd "echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf && sysctl -p"
    print_cmd "systemctl restart mysqld"
    echo "短期缓解:降低buffer_pool;长期无为方案:cgroups限制MySQL内存、增加物理内存/swap" | tee -a "$OUT_DIR/report.log"
elif grep -qi "disk full" "$FOUND_ERR_LOG" 2>/dev/null; then
    echo -e "\n【场景2:磁盘空间耗尽】" | tee -a "$OUT_DIR/report.log"
    print_cmd "mysql -uroot -p -e \"PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);\""
    print_cmd "du -sh $DATA_DIR/* | sort -rh | head -10 # 定位大文件"
    echo "应急清理binlog;长期预防:配置binlog自动过期、磁盘使用率监控告警" | tee -a "$OUT_DIR/report.log"
elif grep -qi "corrupt\|tablespace\|assertion failed" "$OUT_DIR/mysqld_error.log"; then
    echo -e "\n【场景3:InnoDB表空间/数据文件损坏】" | tee -a "$OUT_DIR/report.log"
    print_cmd "sed -i 's/#innodb_force_recovery=.*/innodb_force_recovery=1/' $SELECTED_CNF"
    print_cmd "systemctl start mysqld && mysqldump -u root -p --all-databases > full_backup.sql"
    echo "辩证权衡:RPO优先→逐级恢复导出数据;RTO优先→直接使用备份重建实例" | tee -a "$OUT_DIR/report.log"
elif grep -qi "i/o error\|read-only file system" "$OUT_DIR/dmesg_oom_io_err.log"; then
    echo -e "\n【场景4:磁盘硬件IO故障/文件系统只读】" | tee -a "$OUT_DIR/report.log"
    print_cmd "mount -o remount,rw $DATA_DIR挂载分区"
    print_cmd "umount /data && fsck /dev/sdXX # 停机校验磁盘"
else
    echo -e "\n【无典型底层故障标记,执行全链路补充排查】" | tee -a "$OUT_DIR/report.log"
    print_cmd "ls -la $DATA_DIR # 核对目录属主mysql:mysql"
    print_cmd "ss -tlnp | grep 3306 # 检查端口占用"
    print_cmd "tail -n 100 $FOUND_ERR_LOG # 人工精读完整错误日志"
fi
# 整体论全链路扩展排查清单
echo -e "\n===== 全链路补充手工排查(上下游关联) =====" | tee -a "$OUT_DIR/report.log"
echo "1. 内核硬件层:dmesg -T 查看硬盘、内存硬件报错"
echo "2. 系统守护层:journalctl -u mysqld 完整启停日志"
echo "3. 存储层:检查RAID/云盘磁盘告警、磁盘读写延迟"
echo "4. 业务层:批量写入、大事务、无索引慢SQL触发资源暴涨"
echo "5. 集群层(主从):SHOW SLAVE STATUS 复制线程崩溃、延迟堆积"
echo "6. 备份层:核对定时备份有效性,损坏场景用于数据恢复"
# 最终汇总输出
echo -e "\n${GREEN}==========================================${NC}"
info "MySQL系统化诊断全部采集完成"
print_copy "完整诊断存档目录" "$OUT_DIR"
print_copy "一键查看所有PID/路径清单命令" "cat $KEY_COPY_FILE"
warn "故障处理优先级建议:磁盘满 > OOM内存耗尽 > 数据文件损坏 > IO硬件故障 > 权限/配置错误"
echo -e "${GREEN}==========================================${NC}"

知识扩展

MySQL 故障诊断脚本(collect_mysql_diag.sh)

这是一个用于 Linux 下 MySQL 数据库故障系统化诊断的 Shell 脚本。它能在不干扰业务的前提下,快速收集关键诊断信息,帮助 DBA 或系统管理员定位问题。

#!/bin/bash
# ============================================================================
# MySQL 故障系统化诊断脚本
# 用途:收集 MySQL 运行状态、配置、日志、系统资源等关键信息,用于故障排查
# 适用:Linux 系统,需有 MySQL 客户端访问权限(或本地 socket)
# 作者:DBA Team
# 版本:2026.07
# ============================================================================
# 设置输出目录
DIAG_DIR="/tmp/mysql_diag_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$DIAG_DIR"
# 定义 MySQL 连接参数(建议使用 .my.cnf 或环境变量,避免密码明文)
# 若未设置,默认使用 unix socket 和当前系统用户
MYSQL_CMD="mysql -S /var/lib/mysql/mysql.sock -e"
# 若需远程连接,请修改为:
# MYSQL_CMD="mysql -h 127.0.0.1 -P 3306 -u diag_user -pdiag_pass -e"
# 定义日志文件
DIAG_LOG="$DIAG_DIR/diagnostic.log"
exec > >(tee -a "$DIAG_LOG") 2>&1
echo "============================================================"
echo "MySQL 诊断信息收集开始于: $(date)"
echo "诊断输出目录: $DIAG_DIR"
echo "============================================================"
# 1. 系统基本信息
echo ">>> 1. 系统基本信息"
uname -a
cat /etc/os-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null
uptime
free -h
df -h
echo ""
# 2. MySQL 版本及运行状态
echo ">>> 2. MySQL 版本及运行状态"
$MYSQL_CMD "SELECT VERSION();"
$MYSQL_CMD "SHOW STATUS LIKE 'uptime';"
$MYSQL_CMD "SHOW VARIABLES LIKE 'port';"
$MYSQL_CMD "SHOW VARIABLES LIKE 'datadir';"
echo ""
# 3. MySQL 配置文件(过滤注释和空行)
echo ">>> 3. MySQL 配置文件内容"
if [ -f /etc/my.cnf ]; then
    grep -v '^#' /etc/my.cnf | grep -v '^$' > "$DIAG_DIR/my.cnf"
    cat "$DIAG_DIR/my.cnf"
elif [ -f /etc/mysql/my.cnf ]; then
    grep -v '^#' /etc/mysql/my.cnf | grep -v '^$' > "$DIAG_DIR/my.cnf"
    cat "$DIAG_DIR/my.cnf"
else
    echo "未找到 my.cnf"
fi
echo ""
# 4. 全局状态变量(关键指标)
echo ">>> 4. 关键状态变量"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Threads_connected';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Threads_running';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Max_used_connections';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Slow_queries';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Questions';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Com_select';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Com_insert';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Com_update';"
$MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Com_delete';"
echo ""
# 5. 当前进程列表(过滤用户和状态)
echo ">>> 5. 当前进程列表(前50个)"
$MYSQL_CMD "SHOW PROCESSLIST;" | head -n 50 > "$DIAG_DIR/processlist.txt"
cat "$DIAG_DIR/processlist.txt"
echo ""
# 6. InnoDB 引擎状态(关键信息)
echo ">>> 6. InnoDB 引擎状态(部分)"
$MYSQL_CMD "SHOW ENGINE INNODB STATUS\G" > "$DIAG_DIR/innodb_status.txt"
# 提取关键部分:锁等待、事务、I/O
grep -A 10 "LATEST DETECTED DEADLOCK" "$DIAG_DIR/innodb_status.txt"
grep -A 20 "TRANSACTIONS" "$DIAG_DIR/innodb_status.txt" | head -n 30
grep -A 10 "FILE I/O" "$DIAG_DIR/innodb_status.txt"
echo ""
# 7. 复制状态(如果启用)
echo ">>> 7. 复制状态"
$MYSQL_CMD "SHOW SLAVE STATUS\G" > "$DIAG_DIR/slave_status.txt"
if [ -s "$DIAG_DIR/slave_status.txt" ]; then
    grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Last_Err" "$DIAG_DIR/slave_status.txt"
else
    echo "未启用复制或无法获取复制状态"
fi
echo ""
# 8. 慢查询日志(最近50行)
echo ">>> 8. 慢查询日志(最近50行)"
SLOW_LOG=$(mysql -N -e "SHOW VARIABLES LIKE 'slow_query_log_file';" | awk '{print $2}')
if [ -f "$SLOW_LOG" ]; then
    tail -n 50 "$SLOW_LOG" > "$DIAG_DIR/slow_query.log"
    cat "$DIAG_DIR/slow_query.log"
else
    echo "未找到慢查询日志文件,请确认 slow_query_log 已开启"
fi
echo ""
# 9. 错误日志(最近100行)
echo ">>> 9. MySQL 错误日志(最近100行)"
ERROR_LOG=$(mysql -N -e "SHOW VARIABLES LIKE 'log_error';" | awk '{print $2}')
if [ -f "$ERROR_LOG" ]; then
    tail -n 100 "$ERROR_LOG" > "$DIAG_DIR/error.log"
    cat "$DIAG_DIR/error.log"
else
    echo "未找到错误日志文件"
fi
echo ""
# 10. 系统资源使用情况(MySQL 相关)
echo ">>> 10. 系统资源使用"
ps aux | grep -E 'mysqld|mysql' > "$DIAG_DIR/mysql_processes.txt"
cat "$DIAG_DIR/mysql_processes.txt"
echo ""
iostat -x 1 3 > "$DIAG_DIR/iostat.txt" 2>/dev/null
cat "$DIAG_DIR/iostat.txt"
echo ""
# 11. 磁盘 I/O 和文件系统信息
echo ">>> 11. 数据目录磁盘使用"
datadir=$(mysql -N -e "SHOW VARIABLES LIKE 'datadir';" | awk '{print $2}')
if [ -d "$datadir" ]; then
    du -sh "$datadir" 2>/dev/null
    ls -la "$datadir" | head -n 20
fi
echo ""
# 12. 网络连接状态(MySQL 端口)
echo ">>> 12. MySQL 端口连接数"
ss -tunap | grep -c 3306
ss -tunap | grep 3306 | head -n 20
echo ""
# 13. 最后,打包所有收集的文件
echo "============================================================"
echo "诊断信息收集完成,输出目录: $DIAG_DIR"
tar -czf "$DIAG_DIR.tar.gz" -C /tmp "$(basename "$DIAG_DIR")"
echo "打包文件: $DIAG_DIR.tar.gz"
echo "请将打包文件发送给 DBA 进行分析。"
echo "============================================================"
# 退出前提示
echo "注意:部分信息可能包含敏感数据,请妥善保管。"
exit 0

使用方法

将脚本保存为 collect_mysql_diag.sh,并赋予执行权限:

chmod +x collect_mysql_diag.sh

修改连接参数(可选):如果 MySQL 使用非默认 socket 或需密码,修改脚本开头的 MYSQL_CMD 变量。

执行脚本

./collect_mysql_diag.sh

获取结果:脚本会在 /tmp 下生成形如 mysql_diag_YYYYMMDD_HHMMSS.tar.gz 的压缩包,包含所有诊断文件。

到此这篇关于Linux下MySQL数据库故障系统化诊断的脚本分享的文章就介绍到这了,更多相关MySQL数据库故障诊断内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈linux下的一些常用函数的总结(必看篇)

    浅谈linux下的一些常用函数的总结(必看篇)

    下面小编就为大家带来一篇浅谈linux下的一些常用函数的总结(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • 阿里云ECS实例设置用户root密码和远程连接的方法

    阿里云ECS实例设置用户root密码和远程连接的方法

    这篇文章主要介绍了阿里云ECS实例设置用户root密码和远程连接的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 关于VPS内存不足的一些说明和解决办法

    关于VPS内存不足的一些说明和解决办法

    关于VPS内存不足的一些说明和解决办法,需要的朋友可以参考下。
    2011-11-11
  • VMware虚拟机安装Centos操作系统的教程

    VMware虚拟机安装Centos操作系统的教程

    这篇文章主要为大家详细介绍了VMware虚拟机安装Centos操作系统的教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Linux服务器选择什么版本好

    Linux服务器选择什么版本好

    服务器选择什么版本的linux,这个问题是个老生常谈的问题,每个月都有人讨论,根据我运维过1000台 server的经验,回答如下
    2014-03-03
  • 如何使用​win10内置的linux系统启动spring-boot项目

    如何使用​win10内置的linux系统启动spring-boot项目

    这篇文章主要介绍了如何使用​win10内置的linux系统启动spring-boot项目,需要的朋友可以参考下
    2020-07-07
  • 将宝塔面板linux版装在/www以外的目录的方法

    将宝塔面板linux版装在/www以外的目录的方法

    很多云VPS系统盘,也就是根目录(系统盘)都是10个G,宝塔安装完整环境基本5个G没有了,用了不到几个月,随着日志文件等乱七八糟的东西增加,面板就提示根目录低于1个G,随后mysql就莫名其妙挂掉,这里就为大家分享一下将面板安装到别的目录的方法
    2018-05-05
  • Linux操作系统之逻辑卷管理LVM详解

    Linux操作系统之逻辑卷管理LVM详解

    文章介绍了Linux系统中的逻辑卷管理(LVM)技术,包括LVM的基本概念、卷类型(线性卷、条带卷)、操作(创建物理卷、卷组、逻辑卷,挂载等)和扩容等方法,以及常用命令总结,Lvm提供灵活的的存储管理方式,适用于需要动态扩展存储空间的场景
    2026-04-04
  • Linux中VirtualBox的虚拟机开机自启方式

    Linux中VirtualBox的虚拟机开机自启方式

    本文介绍如何通过创建start.sh脚本并设置开机自启路径,实现VirtualBox虚拟机的开机自动运行,包含检查运行状态、脚本编辑及权限配置步骤
    2025-09-09
  • 配置iptables,把80端口转到8080的简单方法

    配置iptables,把80端口转到8080的简单方法

    下面小编就为大家带来一篇配置iptables,把80端口转到8080的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,祝大家游戏愉快哦
    2016-12-12

最新评论