PHP 连接数据库服务器的本质,是 PHP 通过 MySQL 客户端协议(或 PDO 驱动)与数据库进程建立一条 TCP 连接,完成身份认证后,在连接上发送 SQL 语句并读取结果集,最后关闭连接。换句话说,PHP 本身不会“直接读写”数据库文件,它只是通过网络把 SQL 发过去,真正干活的始终是数据库服务端的进程。
PHP 连接数据库时,网络层到底发生了什么
很多新手以为 new mysqli() 打开数据库”,其实这一行代码背后藏着一整套流程,理解它,后面出现的各种报错才有方向可查。
一次完整连接由四步组成
- PHP 脚本通过扩展(mysqli 或 PDO_MySQL)调用底层的 MySQL 客户端库。
- 客户端库向目标 IP 和端口(默认 3306)发起 TCP 三次握手,注意是 TCP,不是 HTTP,所以不存在“跨域”的概念。
- 握手成功后进入认证阶段:服务端发送挑战串,客户端用用户名、密码哈希和权限表进行校验,同时协商字符集。
- 认证通过后,连接保持打开,PHP 在这条连接上循环执行查询;脚本结束或手动 close 时,连接被释放。
业内专家指出,绝大多数“连不上数据库”的故障,都出在第二步和第三步要么端口不通,要么账号的 host 授权不匹配。
三种连接方式,选错会踩坑
PHP 里能连 MySQL 的手段主要有三套,行为差异不小:
| 方式 | 是否支持预处理 | 是否支持多数据库 | 典型适用场景 |
|---|---|---|---|
| mysql_ 函数 | 不支持 | 不支持 | 已在新版 PHP 中移除,只出现在老项目 |
| mysqli | 支持 | 不支持 | 只对接 MySQL,追求轻量 |
| PDO | 支持 | 支持 | 多数据库兼容、团队统一数据层 |
据 PHP 官方文档说明,mysql_ 系列函数自 PHP 7.0 起已被彻底移除,如果你的老代码还在用它,升级 PHP 版本时必然白屏,这不是数据库的问题,是扩展没了。
php怎么连接mysql数据库:从零跑通的一段可运行代码
先给结论:准备四个要素,写六行代码,就能连上,剩下的都是异常处理和安全加固。
第一步:确认连接四要素
- 主机地址:本机写
0.0.1,不要习惯性写localhost,后者在部分环境下会走 Unix Socket 而不是 TCP,容易和远程连接的排查逻辑混淆。 - 端口:默认
3306,云数据库经常改成自定义端口。 - 账号密码:应用专用账号,不要用 root 跑业务。
- 库名与字符集:字符集统一
utf8mb4,否则 emoji 和部分生僻字会存成问号。
第二步:mysqli 面向对象写法
$mysqli = new mysqli('127.0.0.1', 'app_user', '你的密码', 'shop', 3306);
if ($mysqli->connect_errno) {
error_log('DB connect failed: ' . $mysqli->connect_error);
exit('服务暂时不可用');
}
$mysqli->set_charset('utf8mb4');
$res = $mysqli->query('SELECT id, name FROM goods LIMIT 5');
while ($row = $res->fetch_assoc()) {
echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');
}
$mysqli->close();
第三步:PDO 写法,更适合长期维护的项目
$dsn = 'mysql:host=127.0.0.1;port=3306;dbname=shop;charset=utf8mb4';
$pdo = new PDO($dsn, 'app_user', '你的密码', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$stmt = $pdo->prepare('SELECT name FROM goods WHERE id = ?');
$stmt->execute([$id]);
$row = $stmt->fetch();
把 ATTR_EMULATE_PREPARES 设为 false,是让预处理真正交给 MySQL 服务端执行,而不是 PHP 端拼接字符串,这是防注入的关键开关。
php pdo与mysqli连接数据库有什么区别,项目里该怎么选
这个问题在技术群里几乎天天有人问,答案取决于你的项目边界,而不是哪个“更高级”。
能力对比
- 数据库兼容:PDO 支持 MySQL、PostgreSQL、SQLite 等多种驱动,切换时只改 DSN;mysqli 只认 MySQL。
- 命名参数:PDO 支持
id这种具名占位符,语句可读性好;mysqli 只能用 。 - 性能:单看连接开销,两者差距很小,行业共识认为,真正影响吞吐的是连接复用和索引设计,而不是这两个扩展的选择。
- 学习成本:mysqli 的 API 与老 mysql 函数相似,迁移成本低;PDO 的异常模型更现代。
场景化建议
- 老项目只连 MySQL、短期内不重构:继续用 mysqli,改动面最小。
- 新项目、可能换库、团队要求统一数据访问层:直接上 PDO。
- 需要连接池或更高并发:两者都不够,得引入连接代理或框架自带的连接管理组件。
php连接远程数据库服务器超时怎么解决
本地能连、换到远程就报 Connection timed out 或 Can't connect to MySQL server,这类问题有固定的排查顺序,按下面走,基本能定位。
按顺序执行的排查清单
- 先测端口通不通:`nc -zv 10.0.0.8 3306`,或者 `telnet 10.0.0.8 3306`,不通就是网络或防火墙问题,跟 PHP 无关。
- 看服务端有没有监听公网:登录数据库服务器执行 `ss -lntp | grep 3306`,如果只显示 `127.0.0.1:3306`,说明 `my.cnf` 里的 `bind-address` 被限制在本机,改成 `0.0.0.0` 或具体内网 IP 后重启服务。
- 检查账号授权范围:`SELECT user, host FROM mysql.user;` 只允许 `localhost` 的账号无法从外部登录,需要补一条 `’app_user’@’%’` 或指定网段的授权。
- 确认安全组与防火墙:云服务器普遍有双层限制,操作系统防火墙放行了,云平台的安全组没放行,照样超时。
- 把连接超时显式设短,避免页面卡死:PDO 在 DSN 后加 `[‘PDO::ATTR_TIMEOUT’ => 3]`,mysqli 用 `$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 3)`。
华南地区项目上云时容易忽略的一个点
广州、深圳不少团队把数据库放在同城的云数据库实例上,跨可用区访问时延通常在毫秒级,看起来没问题,但如果 PHP 应用部署在另一个城市的机房,一次查询多出几十毫秒,页面里循环查几十次就会明显变慢,这类情况优先考虑把应用和数据库放在同一地域,或者改成批量查询减少往返次数,而不是一味调大超时时间。
php连接云数据库,一年大概要花多少钱
成本主要由三块构成:实例规格、存储空间、公网流量,入门级共享型实例按月付费通常处于百元量级,一年下来常见在千元上下;如果开了公网地址并按流量计费,账单会随访问量浮动,对中小站点来说,把数据库设为内网访问、只让应用服务器连,是最省钱也最安全的做法公网端口暴露出去,除了多花钱,还会带来被扫描爆破的风险。
连接建立之后,还有几件必须做的事
用长连接还是短连接
PHP-FPM 模式下每个请求默认新建连接,请求结束即释放,并发高时,频繁握手会消耗数据库资源,可以在 PDO 中加 PDO::ATTR_PERSISTENT => true 复用连接,但要清楚代价:持久连接不会在请求结束时回滚未提交的事务,一旦业务代码中途异常退出,脏连接会被下一个请求继承,用不用,取决于代码的健壮程度。
别把密码写死在代码里
把账号密码放到环境变量或独立的配置文件,并确保该文件不在 Web 根目录下。.env 文件被直接访问导致泄露的事件,每年都有发生,数据库账号遵循最小权限原则:只给业务库的增删改查权限,不给 DROP、不给 FILE。
字符集与时间zone统一
连接建立后显式执行 SET NAMES utf8mb4(PDO 在 DSN 里写 charset=utf8mb4 即可),并确认 PHP 与 MySQL 的时区一致,否则订单时间、日志时间会相差八小时,排查起来非常折磨人。
PHP连接数据库服务器常见疑问解答
PHP 连接数据库报“Access denied for user”是什么原因?
认证失败,通常三选一:密码错了;账号的 host 授权不匹配(比如只授权了 localhost,却从远程 IP 连接);MySQL 8 默认认证插件为 caching_sha2_password,而旧版客户端库不支持,第三种可以通过升级 PHP 的 mysqlnd 驱动,或把该账号改为 mysql_native_password 解决,改完记得 FLUSH PRIVILEGES。
为什么本地测试正常,部署到服务器就连接失败?
先区分是代码问题还是环境问题,在服务器上执行一次 php -r "var_dump(extension_loaded('pdo_mysql'));",返回 false 说明扩展没装,装完重启 PHP-FPM 即可,返回 true 就继续按端口、安全组、账号授权的顺序查,绝大多数情况问题不在 PHP 代码本身。
PHP 连接数据库时要不要用连接池?
PHP 是“请求即进程”的模型,没有常驻进程内的连接池概念,所谓连接池通常由外部组件提供,比如数据库中间件或框架封装的连接管理器,访问量不大的站点,用持久连接配合合理的 max_connections 设置就够了;只有当并发连接数长期接近数据库上限时,引入连接池才有实际收益。
回到最初的问题:PHP 连接数据库服务器,本质就是一次带认证的 TCP 会话,选对扩展、配对权限、打通网络,这三件事做到位,剩下的都是细节优化。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/792800.html


