MySQL连接被拒绝Connection refused逐层排查思路

    发布时间:2026-09-19 04:31 更新时间:2026-09-19 04:31 阅读量:0

    连 MySQL 时看到 Can't connect to MySQL server ... (111) 或 Connection refused,和密码错、权限不足是两回事。密码错误的报错是 Access denied,而 Connection refused 说明 TCP 握手阶段就被拒绝了,根本没走到账号验证那一步。换句话说,客户端发出的包没有找到愿意接收它的服务。原因通常落在三个层面:套接字文件路径不对、MySQL 只监听了回环地址、或者中间有防火墙把端口拦掉。本文按从上到下的顺序拆一遍,帮你把排查范围一步步收窄。

    先分清两种连接方式:socket 与 TCP

    MySQL 有两种连接通道,报错表现和排查方向完全不同。第一种是本地 socket 文件,Linux 上默认常在 /var/lib/mysql/mysql.sock,具体路径以 my.cnf 里 socket= 的配置和实际环境为准。用 mysql -u root -p 不带 -h 时,客户端默认走 socket;第二种是 TCP,用 -h 127.0.0.1 或指定 IP 时走网络协议,默认端口 3306。

    很多人遇到的现象是:不带 -h 能进,加了 -h 127.0.0.1 就报错,或者反过来。这正好说明问题出在某一通道上,而不是账号密码。排查第一步就是确认客户端到底在连哪儿。可以用下面这条命令把 socket 路径和连接方式显式打印出来,避免靠猜:

    # 查看客户端实际使用的 socket 路径与端口配置
    mysql --print-defaults
    

    显式指定 socket 连接

    mysql -u root -p --socket=/var/lib/mysql/mysql.sock

    显式走 TCP 回环

    mysql -u root -p -h 127.0.0.1 -P 3306

    如果 socket 路径对不上,客户端会报 Can't connect to local MySQL server through socket,这类报错字面上也带 refused,但根因是文件不存在或权限不对。可以先用 ls -l 看一眼 socket 文件是否真的存在,再用 mysqladmin --socket=... ping 验证服务端是否在正常响应。注意,socket 文件所在目录的权限要让 mysql 用户和连接用户都能访问,否则同样连不上。

    查监听地址:bind-address 只开了回环

    TCP 报 refused 最常见的原因是 MySQL 只监听了 127.0.0.1,远程或容器外访问自然被拒。MySQL 的 bind-address 参数决定监听哪个地址,老版本默认可能是 127.0.0.1,新版本(如 8.0)默认多为 * 即全部地址,具体以你安装的版本和发行版配置为准。先用 ss 确认服务端到底在听哪个地址和端口:

    # 查看 3306 端口的监听状态与进程
    ss -lntp | grep 3306
    

    输出示例:LISTEN 0 151 127.0.0.1:3306 ... 表示只监听回环

    查看 mysqld 进程的启动参数

    ps aux | grep mysqld

    如果只看到 127.0.0.1:3306,说明外部连接必然 refused。这时要改配置文件,通常是 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf,把 bind-address 改成 0.0.0.0 或注释掉(注释掉的行为随版本变化,建议显式写成 0.0.0.0 更可控)。改完必须重启 mysqld 才生效,注意重启会短暂中断现有连接,生产环境建议在低峰期操作。

    [mysqld]
    

    监听所有 IPv4 地址,允许外部连接

    bind-address = 0.0.0.0

    端口保持默认

    port = 3306

    改完监听地址后,还要确认用户授权范围。如果账号是 'user'@'localhost',即便端口通了,从远程连也会被拒(报错可能是 Access denied 或 host 不允许)。这一步用 SELECT user, host FROM mysql.user; 核对,把需要远程访问的账号改成对应网段,比如 'user'@'192.168.1.%'。别为了省事直接开 '%',安全边界会变薄。

    查防火墙与云安全组

    监听地址没问题、账号也对,还是 refused,就要看包有没有被拦。注意一个细节:如果防火墙是 DROP 策略,客户端会超时卡住;如果是 REJECT,才会立刻返回 refused。所以“秒拒”往往指向 REJECT 规则或根本没有服务在听。先在服务端本机用 127.0.0.1 连一次,本机通、远程不通,基本就是网络层拦截。

    这里要同时检查三层:本机 firewalld/iptables、云厂商安全组、以及中间的硬件或软件防火墙。以 firewalld 为例,放行 3306 并让配置立即生效:

    # 查看当前放行的服务与端口
    firewall-cmd --list-all
    

    永久放行 3306/tcp 并重载

    firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload

    确认规则已生效

    firewall-cmd --query-port=3306/tcp

    如果用的是 iptables,规则写法与链名有关,建议先 iptables -L -n --line-numbers 看清顺序再插规则,别盲目 append 导致被前面的 DROP 覆盖。云服务器还要去控制台检查安全组入方向是否放行了 3306,安全组规则通常在实例外部生效,本机 firewalld 通了也未必能过。另外,SELinux 在某些发行版上也会影响非标准端口,若你把 MySQL 改到 3306 以外的端口,需要确认 SELinux 是否允许,具体策略以官方文档和实际环境为准。

    排查顺序建议固定下来:先本机 socket 通不通,再本机 TCP 通不通,然后同网段其他机器通不通,最后外网通不通。每过一层就缩小一次范围,比反复重启服务有效得多。定位到具体层面后,再决定是改配置、调监听地址,还是补防火墙规则。改完记得用 mysqladmin -h 目标IP -u 用户 -p ping 验证一次,确认返回 mysqld is alive 才算收工。日常运维里,把监听地址、账号 host 范围和防火墙规则这三项写进部署检查清单,能省掉大量重复排障时间。

    继续阅读

    📑 📅
    systemd-journald 日志转发远程 syslog:rsyslog 对接与丢日志排查 2026-09-19
    Nginx 静态资源 404 与权限被拒排查:root、alias、try_files 的坑 2026-09-18
    Linux网卡丢包与TCP重传排查:ip -s link、ss -ti与ethtool实战 2026-09-18
    journald 日志占满 /var/log:持久化与容量限制配置 2026-09-18
    Docker容器时区不对?TZ变量与localtime挂载的正确用法 2026-09-17
    Docker容器DNS解析异常排查:resolv.conf与自定义网络 2026-09-19
    PHP-FPM 进程数怎么调:pm.max_children 与内存估算 2026-09-19
    Nginx gzip 与 Brotli 压缩配置实战:静态资源体积优化 2026-09-19
    Docker 容器内 CPU 被限流排查:cfs_quota、cpuset 与 top 显示异常 2026-09-19
    Nginx 与后端长连接调优:keepalive 与 upstream 复用 2026-09-20