connection refused 错误主因是 mysql 服务未运行或端口被防火墙拦截,需先检查服务状态、端口监听(bind-address)、用户授权及认证插件兼容性。

mysqli_connect() 连不上,错误提示 Connection refused 怎么办
绝大多数连不上不是代码写错,而是 MySQL 服务根本没在跑,或者端口被防火墙拦了。先确认本地 MySQL 是否运行:sudo systemctl status mysql(Linux)或打开「服务」里找 mysql(Windows)。默认端口是 3306,如果改过,mysqli_connect() 的第四个参数必须显式传进去,不能只靠默认值。
常见错误现象:mysqli_connect(): (HY000/2002): Connection refused —— 这基本等于“压根没连到 MySQL 进程”。别急着查用户名密码,先 ping 不通、telnet 不通,就不用往下试了。
- 检查 MySQL 是否监听
127.0.0.1:看配置文件/etc/mysql/mysql.conf.d/mysqld.cnf里bind-address是不是127.0.0.1或0.0.0.0,不是的话连本地都会被拒 - 远程连接?确保用户授权用了
'user'@'%'而非'user'@'localhost',后者在某些系统下走 socket 而非 TCP,mysqli_connect()强制走 TCP 就会失败 - PHP 和 MySQL 版本差异大(比如 PHP 8.2 + MySQL 8.0+),默认认证插件可能是
caching_sha2_password,老 mysqli 扩展不认,得在 MySQL 里执行:ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_pass';
用 mysqli 面向对象方式还是过程式?选哪个更稳
两者底层完全一样,没性能差别,但面向对象写法能避免变量污染、更容易做封装。过程式写法里所有函数都依赖上一步返回的 $conn 资源,一旦漏判 mysqli_connect() 返回 false,后面 mysqli_query($conn, ...) 直接报 Warning: mysqli_query(): invalid mysqli object。
推荐无脑用面向对象,出错时异常明确,且 mysqli 类本身支持 set_charset()、real_escape_string() 等方法链式调用:
立即学习“PHP免费学习笔记(深入)”;
citySHOP是一款集CMS、网店、商品、分类信息、论坛等为一体的城市多用户商城系统,已完美整合目前流行的Discuz! 6.0论坛,采用最新的5.0版PHP+MYSQL技术。面向对象的数据库连接机制,缓存及80%静态化处理,使它能最大程度减轻服务器负担,为您节约建设成本。多级店铺区分及联盟商户地图标注,实体店与虚拟完美结合。个性化的店铺系统,会员后台一体化管理。后台登陆初始网站密匙:LOVES
$conn = new mysqli($host, $user, $pass, $db, $port);
if ($conn->connect_error) {
die('连接失败:' . $conn->connect_error);
}
$conn->set_charset('utf8mb4');- 过程式必须每次手动检查
mysqli_connect()返回值,漏一次就崩 - 面向对象方式下,
$conn->query()失败直接返回false,不会静默吞错;而过程式mysqli_query()在开启mysqli.report之前,默认也不报错 - 如果项目已用 PDO,别为了“统一”硬切 mysqli —— 混用反而增加维护成本
mysqli_real_escape_string() 还安全吗?为什么总提醒用预处理
它没被废弃,但仅限于“字符串拼接 SQL”这种旧写法下兜底。只要中间经过任何变量拼接,比如 "SELECT * FROM users WHERE name = '" . mysqli_real_escape_string($conn, $_GET['name']) . "'",就存在绕过风险:比如 MySQL 设置了 sql_mode=NO_BACKSLASH_ESCAPES,或客户端编码与连接层不一致,real_escape_string() 就可能失效。
真正防注入只有两条路:预处理(prepared statement)或严格白名单校验。预处理把 SQL 结构和数据彻底分离,MySQL 服务端自己解析参数,根本不会当 SQL 执行。
- 预处理不是“更麻烦”,而是更少出错:用
$stmt = $conn->prepare("SELECT * FROM t WHERE id = ?"),然后$stmt->bind_param("i", $id),类型"i"、"s"写错才真会翻车 -
mysqli_real_escape_string()必须传入有效的$conn对象,如果连接已断开还调用,会警告并返回空字符串,结果查不到数据还找不到原因 - 对非字符串字段(如数字 ID、时间戳),别用
escape,直接类型转换更干净:$id = (int)$_GET['id']
连接池、长连接、mysqli_pconnect() 到底要不要用
PHP-FPM 模式下,mysqli_pconnect() 基本没意义,甚至有害。每个 worker 进程会维持自己的持久连接,连接数会指数级上涨,很快打满 MySQL 的 max_connections。官方文档也明确说:“不建议在 Web 环境中使用”。真正的连接复用靠 MySQL 自身的连接池(MySQL 8.0+)或中间件(如 ProxySQL),PHP 层只需用好短连接 + 合理超时。
关键其实是三个超时参数:连接超时(connect_timeout)、等待响应超时(read_timeout)、发送超时(write_timeout)。默认都是 60 秒,网络卡顿或查询慢时,请求就挂死在那里,拖垮整个 FPM 进程。
- 设连接超时:
$conn = mysqli_init(); mysqli_options($conn, MYSQLI_OPT_CONNECT_TIMEOUT, 5); mysqli_real_connect(...) - 查慢查询?加
mysqli_options($conn, MYSQLI_OPT_READ_TIMEOUT, 10),避免一个慢 SQL 卡住整个请求 - 别信“长连接省资源”——PHP 请求生命周期短,连接建立开销远小于维护闲置连接的成本
复杂点在于:错误处理必须覆盖连接中断、查询超时、字符集不匹配这三类问题,而它们抛出的错误码完全不同,mysqli_sqlstate() 和 mysqli_errno() 得分开判断。很多人只 catch mysqli_connect_error,结果线上偶尔 502 却查不到日志。










