PHP 8.1 连不上远程 MySQL 主因是 MySQL 服务端未开放远程访问:需将 bind-address 改为 0.0.0.0 并重启服务,创建指定 IP 的用户并授权,同时放行防火墙及云服务器安全组的 3306 端口。

PHP 8.1 连不上远程 MySQL,90% 不是代码问题,而是 MySQL 服务端压根没“开门”——mysqli_connect() 报 Connection refused 或 Host 'x.x.x.x' is not allowed to connect,得先查服务、端口、权限三层,再动 PHP 代码。
MySQL 服务是否监听 3306 并允许外部连接
PHP 8.1 自身不拦连接,但 MySQL 默认只听 127.0.0.1。如果 bind-address = 127.0.0.1(常见于 /etc/mysql/mysql.conf.d/mysqld.cnf),那它连本机局域网 IP 都不认,更别说远程 PHP 了。
- 确认当前绑定地址:
sudo grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf,必须是0.0.0.0或具体 PHP 服务器 IP - 改完立即重启:
sudo systemctl restart mysql - 验证是否真在监听:
ss -tlnp | grep :3306,输出里要有*:3306,不是127.0.0.1:3306 - 别信
ping通就等于能连——ping走 ICMP,MySQL 走 TCP/3306,完全两码事
用户权限是否匹配“从哪来 + 用谁连”
MySQL 的 user@host 是精确匹配项。'app_user'@'localhost' 和 'app_user'@'127.0.0.1' 是两个账号;'app_user'@'%' 看似方便,但在腾讯云/GCP 上常被安全组直接拦截,实际无效。
- 登录 MySQL 后执行:
SELECT User, Host FROM mysql.user WHERE User = 'your_user';,看返回的Host值是不是你 PHP 连接时用的 IP(比如203.0.113.45) - 创建用户务必带来源 IP:
CREATE USER 'app_user'@'203.0.113.45' IDENTIFIED BY 'strong_password'; - 授权范围最小化:
GRANT SELECT, INSERT ON mydb.* TO 'app_user'@'203.0.113.45';,别用GRANT ALL ON *.* - 执行完必须
FLUSH PRIVILEGES;,否则权限不生效
防火墙、安全组、SELinux 是否悄悄丢包
本地 ss -tlnp 显示 3306 在监听,systemctl status mysql 显示 active,但 PHP 还是 Connection refused?八成卡在这一层。
立即学习“PHP免费学习笔记(深入)”;
- Linux 防火墙检查:
sudo ufw status(Ubuntu)或sudo firewall-cmd --list-ports(CentOS),确保 3306/tcp 入站放行 - 云服务器(阿里云/腾讯云/AWS)必须进控制台 → 安全组 → 添加入方向规则:端口
3306,协议TCP,源 IP 填 PHP 服务器公网 IP 或段(如203.0.113.45/32) - Docker 场景下,PHP 容器里写
localhost是连自己,不是宿主机 MySQL;该用host.docker.internal(Mac/Windows)或宿主机真实内网 IP(Linux) - SELinux 临时关闭验证:
sudo setenforce 0;若恢复后仍要连,需配策略而非永久关
PHP 8.1 连接代码中容易错的细节
PHP 8.1 默认启用 mysqli 扩展,但参数填错或字符集漏设,会导致连上却读不出中文、或预处理失败。
- 别用
localhost当主机名——它在部分系统走 Unix socket,远程必须用 IP:$conn = mysqli_connect('203.0.113.45', $user, $pass, $db, 3306); - 显式指定字符集,避免乱码:
mysqli_set_charset($conn, 'utf8mb4');(放在mysqli_connect()之后、查询之前) - PDO 方式注意 DSN 中密码含
@、/会解析错误,得用urlencode()编码:$dsn = "mysql:host=203.0.113.45;dbname=mydb;charset=utf8mb4"; - 测试时先简化:去掉数据库名,只连服务端,看
mysqli_connect()返回是否为 resource;再加库名,再加查询
最常被跳过的一步:改完 MySQL 配置、建完用户、开了防火墙,却忘了重启 mysql 服务——sudo systemctl restart mysql 这条命令,少一次就全白搭。



















