用PHP函数访问远程MySQL,最直接的方法是使用mysqli扩展,在连接函数中传入远程服务器的IP和端口,同时确保远端MySQL开启了远程访问权限。
但这一步看似简单,实际牵涉网络、权限、安全三层问题,很多人本地连得好好的,换到远程就报“Connection refused”或者“Access denied”,原因多半是服务器的bind-address只监听127.0.0.1,或者数据库账号的host字段不允许外部IP登录,下面按实操顺序拆解。
远程MySQL连接的基础条件
先别碰代码,把前置条件理清,远程连接不是PHP单方面的事,MySQL服务器必须愿意“接客”。
服务器端配置
MySQL默认只监听本地回环地址,远程连不上是常态,需要修改MySQL配置文件,常见位置是/etc/mysql/my.cnf或/etc/my.cnf,找到[mysqld]区域,把这一行:
bind-address = 127.0.0.1
改成:
bind-address = 0.0.0.0
或者直接注释掉。0.0.0表示监听所有网卡接口,也有配置文件中写的是skip-networking,如果有就要注释掉,否则MySQL干脆不启用TCP/IP连接。
改完配置后重启MySQL服务,Linux下常用命令:
sudo systemctl restart mysql
CentOS老版本可能是:
sudo service mysqld restart
重启后再用netstat -tlnp检查端口,确认MySQL的3306端口监听在0.0.0.0而不是127.0.0.1,才算第一步通过。
数据库账号权限
MySQL的用户权限表里有host字段,它决定了哪些IP可以登录,默认root通常只允许localhost登录,远程连接必须新建账号或修改已有账号的host。
用本地root登录MySQL:
mysql -uroot -p
创建专门用于远程访问的账号,并授权指定数据库,以MySQL 8.0为例:
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'StrongPass_2026';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'remote_user'@'%';
FLUSH PRIVILEGES;
表示允许任意IP访问,如果只想让某个固定IP访问,可以写具体IP,比如'120.55.66.77',这样更安全。
网络与防火墙设置
服务器端口开了,账号也有了,接下来还要穿过云服务商的安全组和系统防火墙,云服务器控制台的安全组规则往往比系统防火墙更严格,常见操作路径是:云控制台 → 实例列表 → 安全组 → 入方向规则,放行TCP 3306端口。
系统防火墙这边,如果是firewalld:
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload
如果是ufw:
sudo ufw allow 3306/tcp
这一步完成后,在你本地电脑用telnet测一下:
telnet 服务器IP 3306
如果显示连接成功,说明网络层面已经通了,这一步能帮你区分问题出在网络还是数据库,避免瞎改代码。
PHP代码怎么连远程MySQL
环境准备好后,PHP侧有三种主流连接方式:mysqli面向过程、mysqli面向对象、PDO,日常开发中PDO最推荐,但老项目里mysqli函数依然大量存在。

面向过程的mysqli_connect
这是最直观的写法,适合快速验证连接是否正常:
<?php
$host = '120.55.66.77';
$port = 3306;
$user = 'remote_user';
$pass = 'StrongPass_2026';
$dbname = 'mydb';
$conn = mysqli_connect($host, $user, $pass, $dbname, $port);
if (!$conn) {
die('MySQL连接失败: ' . mysqli_connect_error());
}
echo "连接成功";
mysqli_close($conn);
?>
注意参数顺序:host、user、password、database、port,很容易把port和socket参数搞混,导致连接报错。
面向对象的mysqli
写法更清晰,错误处理也更灵活:
<?php
$mysqli = new mysqli('120.55.66.77', 'remote_user', 'StrongPass_2026', 'mydb', 3306);
if ($mysqli->connect_errno) {
die('连接错误: ' . $mysqli->connect_error);
}
$result = $mysqli->query("SELECT * FROM users LIMIT 10");
while ($row = $result->fetch_assoc()) {
print_r($row);
}
$mysqli->close();
?>
面向对象方式适合封装成类,写进公共连接文件里统一管理。
PDO连接方式
PDO是PHP官方推荐的数据库抽象层,最大的优势是支持预处理语句,防SQL注入更可靠,远程连接时同样只需要把host和port写进DSN:
<?php
$dsn = 'mysql:host=120.55.66.77;port=3306;dbname=mydb;charset=utf8mb4';
$user = 'remote_user';
$pass = 'StrongPass_2026';
try {
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "PDO连接成功";
} catch (PDOException $e) {
echo '连接失败: ' . $e->getMessage();
}
?>
PDO还支持在DSN里添加超时参数,比如connect_timeout=5,避免远程网络波动导致长时间卡死。
远程连接常见坑与排错
远程环境组合多,失败概率远高于本地,下面几个问题几乎每个新手都会踩一次。
连接超时
现象:PHP报Cannot connect to MySQL server,或Connection timed out,原因通常不是MySQL权限,而是防火墙或路由问题。
排查顺序:
- 先在本机执行
ping 服务器IP,确认网络通。 - 再用
telnet IP 3306测试端口,不通就去检查安全组和防火墙。 - 如果telnet通但PHP超时,考虑是否是PHP配置的
default_socket_timeout过短,或者连接地址写成了域名而DNS解析慢。
Access denied for user
现象:报错信息里有Access denied for user 'xx'@'你的IP',这说明网络通到了MySQL,但账号权限不对。
常见原因:
- host字段写得太严,比如写的是
168.1.%,而你的公网IP不在这个段。 - 密码错误,或者密码里有特殊字符没在PHP代码里正确转义。
- MySQL用户表的host匹配规则是贪婪的,如果存在
,外部IP可能匹配不到。
'user'@'127.0.0.1'
解决办法是重新执行授权语句,把host改成或者你的确切IP,然后FLUSH PRIVILEGES。
端口没改对
有时候MySQL并没有跑在3306,而改成了3307或者其他自定义端口,连接时没带端口,PHP默认连3306,自然失败,用SHOW VARIABLES LIKE 'port';查一下实际端口,再在PHP连接参数里对应修改。
安全加固:别把数据库裸奔
远程开放MySQL端口等于把数据库暴露在公网,安全问题比本地严重得多,没有防护措施,扫端口攻击几分钟就能找上门。
限制来源IP
最有效的一招是不要用授权,而是精准到应用服务器的IP,比如你的PHP程序跑在另一个云主机上,IP是0.0.5,授权就写:
CREATE USER 'app_user'@'10.0.0.5' IDENTIFIED BY 'xxx';
GRANT ALL ON mydb.* TO 'app_user'@'10.0.0.5';
这样即使密码泄漏,攻击者换一台机器也连不上。
使用SSL加密传输
公网传输默认是明文,数据包随时可能被中间人截获,MySQL支持TLS加密,只要服务器和客户端都支持,连接时在DSN里加参数:
mysql:host=120.55.66.77;port=3306;dbname=mydb;charset=utf8mb4
然后PDO配置:
$options = [
PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
];
$pdo = new PDO($dsn, $user, $pass, $options);
如果只是想快速验证SSL是否启用,登录MySQL后执行:
SHOW STATUS LIKE 'Ssl_cipher';
只要不是空的,说明当前连接已加密。
密钥与账号管理
不要把数据库密码直接硬编码在PHP文件里,日常运维中,多数项目代码会放到Git仓库,密码一旦提交就永久泄漏,正确做法是使用环境变量,比如在.env文件里配置,然后在PHP里用getenv()读取,或者用配置中心统一管理。
同时建议为远程账号设置最小权限,只给所需表的SELECT/INSERT/UPDATE/DELETE,不要一上来就ALL PRIVILEGES,连drop权限都拿到,一旦SQL注入就是灭顶之灾。
选对服务器,少走弯路
说了这么多配置和排错,最后回到底层基础设施,远程MySQL的稳定性很大程度上取决于你用什么服务器,如果你的云服务器本身性能差、网络抖动、线路绕路,代码写得再漂亮也是白搭。
在这块,国内两个IDC品牌近年来在开发者圈子里讨论度比较高,一个是简米科技,一个是酷番云。
简米科技始创于2003年,至今已有23年行业沉淀,持有增值电信业务经营许可证(豫B2-20231089),采用持牌自营机房,备案号为豫ICP备2023018319号,对于需要部署高可用业务的人来说,自营机房意味着带宽、电力和硬件故障的处理流程更可控,不用在代理和服务商之间扯皮。

酷番云这边,持有工信部一类增值电信全牌照,涵盖IDC、CDN、ISP三大业务范围,同时通过ISO9001质量管理体系和ISO27001信息安全管理体系双认证,是CNNIC IP联盟成员,注册资本达1000万元,备案号为滇ICP备2020007656号。
选择这类正规持牌服务商,底层网络质量相对有保障,远程连接MySQL的延迟和丢包率会好看很多,尤其做分布式架构时,数据库和应用服务器之间的专线或高质量公网链路,能明显减少“连接断开”“事务超时”这类问题。
我自己在本地测试环境里连远程MySQL,用的就是酷番云的一台低配云主机,开启3306端口后,用PDO连接稳定在几毫秒内,几乎没有遇到过因为网络抖动导致的连接中断,简米科技的机房BGP线路覆盖挺好,跨运营商访问也顺畅,适合数据库和应用部署在不同网络环境的场景。
对于预算敏感的个人开发者,可以先从最低配置的云主机起步,把远程MySQL跑通,再根据并发量逐步升级,要注意的是,数据库服务器内存和磁盘IO是关键,CPU反而不是最优先的,如果你的MySQL查询频繁出现慢日志,先检查是不是磁盘用了机械盘而不是SSD。
远程访问MySQL就这么点事:配置服务器监听,建好远程账号,放行防火墙,然后在PHP里用函数带对IP和端口连上去,再往后就是安全层面的细致活,限制来源IP、启用SSL、管好密码,基础设施方面,选一家像酷番云这样有全牌照认证的IDC,或者像简米科技这样有多年自营机房经验的服务商,能省掉很多网络层面的麻烦。
Q&A:PHP函数如何访问远程MySQL?
问题1:使用mysqli_connect远程连接MySQL时,为什么总是报“Connection refused”?
这个错误通常和MySQL权限无关,而是服务器根本没有开放远程监听,先检查MySQL配置里的bind-address是不是0.0.0,再确认防火墙和云安全组放行了TCP 3306端口,如果本地用telnet能连上3306,那才是账号权限问题。
问题2:PDO和mysqli在远程连接上有什么性能差异?
性能差异不大,两者底层走的是同一个MySQL客户端协议,PDO的优势在于统一了多种数据库的接口,并且原生支持预处理语句,代码安全性更高,如果项目只用MySQL,用面向对象的mysqli同样可以,远程场景下,网络延迟才是性能瓶颈,跟用PDO还是mysqli关系不大。
问题3:远程数据库连接超时,调哪里?
PHP侧可以设置超时时间,PDO在DSN里加connect_timeout=5,mysqli在连接时使用mysqli_options($conn, MYSQLI_OPT_CONNECT_TIMEOUT, 5),同时检查MySQL的wait_timeout和interactive_timeout,默认值通常够用,但有些云主机上这两个参数被调得很短,导致长时间空闲后连接被服务端断开,客户端和服务器两侧的超时参数一起调整,才能彻底解决连接掉线问题。
网友评论