MySQL 或 MariaDB 一连不上,很多网站就直接趴下。
WordPress 会报:
Error establishing a database connection
应用日志里可能是:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket
ERROR 2003 (HY000): Can't connect to MySQL server on 'x.x.x.x'
Access denied for user
Connection refused
Lost connection to MySQL server
这些报错看起来都像“数据库坏了”,但根因可能完全不同:服务没启动、端口没监听、socket 路径错、磁盘满、MySQL 只监听 127.0.0.1、防火墙拦了 3306、用户授权不对,甚至是 InnoDB 起不来。
这篇按排查顺序来:先分清本机连接失败还是远程连接失败,再查服务、端口、日志、权限和磁盘。不要一上来就开放 3306 到公网,也不要直接重装数据库。
先在 VPS 本机测试:
mysql -u root -p
或者:
mysqladmin -u root -p ping
如果本机都连不上,优先查服务和日志。
如果本机能连,但远程电脑连不上:
mysql -h 你的VPS_IP -P 3306 -u 用户名 -p
那就重点查监听地址、防火墙、安全组、用户授权。
这一步很关键。很多人远程连不上,就去改数据库密码;其实本机连接正常,问题在网络层。也有人本机都连不上,却一直折腾安全组,方向完全反了。
Ubuntu/Debian 上服务名可能是 mysql 或 mariadb。
先看:
systemctl status mysql --no-pager
systemctl status mariadb --no-pager
如果不确定服务名:
systemctl list-units | grep -Ei 'mysql|mariadb'
看最近日志:
journalctl -u mysql --since "30 minutes ago" --no-pager
journalctl -u mariadb --since "30 minutes ago" --no-pager
如果服务没启动,先尝试:
sudo systemctl restart mysql
或:
sudo systemctl restart mariadb
重启后不要只看命令有没有返回,要再次看状态和日志。很多 MySQL/MariaDB 启动失败,真正原因写在日志里。
常见日志位置:
/var/log/mysql/error.log
/var/log/mariadb/mariadb.log
/var/log/mysql/mysql.log
可以这样找:
sudo ls -lh /var/log/mysql/ /var/log/mariadb/ 2>/dev/null
sudo tail -n 100 /var/log/mysql/error.log
如果没有这个文件,也可以用 journal:
journalctl -u mysql -n 100 --no-pager
journalctl -u mariadb -n 100 --no-pager
常见关键词:
| 日志关键词 | 常见方向 |
|---|---|
No space left on device | 磁盘或 inode 满 |
Can't create/write to file | 权限、磁盘、临时目录问题 |
InnoDB: Database was not shutdown normally | 异常关机后恢复 |
InnoDB: Unable to lock ./ibdata1 | 另一个 mysqld 进程或文件锁 |
Bind on TCP/IP port: Address already in use | 3306 被占用 |
Access denied for user | 用户名、密码、授权问题 |
Too many connections | 连接数打满 |
日志比猜测靠谱。先看日志,再决定下一步。
MySQL/MariaDB 对磁盘很敏感。系统盘满了、inode 满了、/tmp 写不了,都可能导致启动失败或写入失败。
先看:
df -h
df -i
再看数据库目录大小:
sudo du -h --max-depth=1 /var/lib/mysql | sort -h
如果磁盘满,先不要随便删 /var/lib/mysql。那是数据库数据目录,删错就是数据丢失。
可以优先清理:
sudo apt clean
journalctl --disk-usage
sudo journalctl --vacuum-time=7d
如果 MySQL binlog 很大,也不要直接 rm。先进入 MySQL 查:
SHOW BINARY LOGS;
再按备份和主从复制情况决定是否清理。没把握时先做快照或备份。
如果服务显示 running,但外部连不上,先看端口:
ss -lntp | grep 3306
你可能看到:
127.0.0.1:3306
0.0.0.0:3306
[::]:3306
区别很大:
127.0.0.1:3306:只允许本机连接0.0.0.0:3306:监听所有 IPv4 地址[::]:3306:监听 IPv6,具体行为看配置
如果你只是 WordPress 和 MySQL 都在同一台 VPS 上,127.0.0.1 反而更安全,不需要开放公网。
如果确实要远程连接,比如应用服务器和数据库拆开,才考虑让 MySQL 监听内网 IP 或指定公网 IP。
MySQL/MariaDB 的监听地址通常由 bind-address 控制。
查配置:
sudo grep -R "bind-address" /etc/mysql/ /etc/my.cnf* 2>/dev/null
常见配置:
bind-address = 127.0.0.1
如果你要允许远程连接,可能会改成:
bind-address = 0.0.0.0
但这里要非常小心。0.0.0.0 代表监听所有网卡,不等于安全允许。还必须配合防火墙、安全组、用户授权,只允许可信 IP 访问。
更推荐绑定内网地址,例如:
bind-address = 10.0.0.5
改完重启:
sudo systemctl restart mysql
ss -lntp | grep 3306
远程连不上 3306,经常不是 MySQL 本身,而是防火墙或云厂商安全组。
本机防火墙:
sudo ufw status verbose
sudo iptables -S
如果用 firewalld:
sudo firewall-cmd --list-all
云厂商安全组也要看:
- 入站是否放行 3306
- 来源 IP 是否限制为你的应用服务器或办公 IP
- 是否放错协议或网卡
- 是否只放了 IPv4,实际走 IPv6
不要把 3306 直接放给 0.0.0.0/0。公网暴露数据库风险非常高,暴力破解和扫描会很快找上门。
如果只是临时管理,优先用 SSH 隧道:
ssh -L 3307:127.0.0.1:3306 root@你的VPS_IP
然后本地连接:
mysql -h 127.0.0.1 -P 3307 -u 用户名 -p
这样数据库仍然只监听本机,远程通过 SSH 加密隧道访问。
MySQL 用户是按 用户名@来源主机 区分的。app@localhost 和 app@% 是两个不同授权。
进入 MySQL 后看用户:
SELECT user, host FROM mysql.user;
查看授权:
SHOW GRANTS FOR 'app'@'localhost';
SHOW GRANTS FOR 'app'@'%';
如果远程应用服务器 IP 是 10.0.0.8,更安全的做法是只授权这个来源:
CREATE USER 'app'@'10.0.0.8' IDENTIFIED BY '强密码';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.0.0.8';
FLUSH PRIVILEGES;
不要为了省事直接:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password';
这类配置是事故高发区。应用用户只给需要的库和权限,不要远程开放 root。
如果报:
Access denied for user 'app'@'x.x.x.x'
重点查:
- 用户名是否正确
- 密码是否正确
host是否匹配来源 IP- 应用是否连到了正确的数据库实例
- MySQL 8 认证插件是否和客户端兼容
看当前用户:
SELECT user, host, plugin FROM mysql.user;
MySQL 8 默认认证插件可能让旧客户端不兼容。不要盲目改 root,可以只给应用用户设置兼容插件,或升级客户端。
如果日志或应用报:
Too many connections
先看当前连接:
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
临时可以提高:
SET GLOBAL max_connections = 200;
但这只是临时。长期要查:
- 应用是否连接池配置太大
- 是否有慢查询卡住连接
- 是否有爬虫或攻击流量
- PHP-FPM/应用进程数是否超过数据库承载能力
- 数据库机器内存是否够
小 VPS 上盲目把 max_connections 调到 1000,可能直接把内存打爆。
如果 MySQL/MariaDB 跑在 Docker 里,先看容器:
docker ps
docker logs 容器名 --tail 100
docker compose ps
docker compose logs --tail 100 mysql
看端口映射:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
容器内测试:
docker exec -it 容器名 mysql -u root -p
宿主机测试:
mysql -h 127.0.0.1 -P 3306 -u root -p
Docker 常见坑:
- 数据卷权限不对
- 数据目录挂载错了
- 环境变量只在首次初始化生效,后面改了没用
- 容器内监听正常,但端口没映射到宿主机
- 应用容器应该连服务名
mysql,却连了127.0.0.1
Docker 场景里,127.0.0.1 是相对容器自己的,不一定是宿主机。
如果网站报数据库连接失败,我一般这样查:
systemctl status mysql --no-pager
systemctl status mariadb --no-pager
journalctl -u mysql --since "30 minutes ago" --no-pager
sudo tail -n 100 /var/log/mysql/error.log
看磁盘:
df -h
df -i
sudo du -h --max-depth=1 /var/lib/mysql | sort -h
看端口:
ss -lntp | grep 3306
本机连接:
mysqladmin -u root -p ping
mysql -u root -p
远程访问才查:
sudo ufw status verbose
sudo iptables -S
sudo grep -R "bind-address" /etc/mysql/ /etc/my.cnf* 2>/dev/null
进入 MySQL 后查:
SELECT user, host, plugin FROM mysql.user;
SHOW PROCESSLIST;
SHOW VARIABLES LIKE 'max_connections';
按这个顺序,基本能把问题分到服务、磁盘、监听、网络、授权、连接数这几类里。
- 本机
mysql -u root -p是否能连 -
systemctl status mysql/mariadb是否正常 -
journalctl和 error.log 有没有明确错误 -
df -h、df -i是否正常 -
/var/lib/mysql是否异常膨胀 -
ss -lntp | grep 3306是否监听 -
bind-address是否符合预期 - UFW / iptables / firewalld 是否拦截
- 云厂商安全组是否只放行可信 IP
- MySQL 用户的
user@host是否匹配来源 - 是否有
Too many connections - Docker 场景是否检查了容器日志、端口映射、数据卷
- 没有把 3306 裸放给全网
数据库连接问题最怕混着查。本机连不上,就先查服务和日志;本机能连、远程不通,再查监听、防火墙、安全组和授权。只要把这几层分开,MySQL/MariaDB 连接不上就不会变成玄学。
