首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 連接 MySQL:localhost vs 127.0.0.1 的底層差異與解決方案

     編輯:PHP 相關知識

PHP 連接 MySQL:localhost vs 127.0.0.1 的底層差異與解決方案

同樣是本機連接,為什麼 localhost 失敗而 127.0.0.1 成功?本文深入解析 Unix Domain Socket 與 TCP 連接的差異、常見故障場景、多種修復方案與最佳實踐配置。

核心差異

主機參數傳輸協議MySQL 端處理適用場景
localhostUnix Domain Socket (檔案)讀取 mysql.sock 路徑同機、高效能、低延遲
127.0.0.1TCP/IP (回環介面)監聽 3306 端口跨容器、Docker、強制 TCP
::1 (IPv6)TCP/IPv6監聽 IPv6 端口IPv6 環境

常見錯誤與原因

Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
  • Socket 文件不存在:MySQL 未啟動、或 datadir 變更導致路徑不一致
  • 權限不足:PHP-FPM 進程用戶無法讀取 socket 文件目錄
  • 配置不一致:php.ini 的 mysqli.default_socket / pdo_mysql.default_socket 指向錯誤路徑

五種解決方案(按推薦順序)

方案 1:統一 Socket 路徑(推薦,效能最佳)

  1. 確認 MySQL 實際 socket 位置:
    mysql -e "SHOW VARIABLES LIKE 'socket';"
    # 或
    cat /etc/my.cnf | grep socket
  2. 同步 PHP 配置(php.ini):
    [MySQLi]
    mysqli.default_socket = /var/run/mysqld/mysqld.sock
    
    [PDO_mysql]
    pdo_mysql.default_socket = /var/run/mysqld/mysqld.sock
  3. 重啟 PHP-FPM:systemctl restart php-fpm

方案 2:強制使用 TCP(通用性最強)

代碼層面指定主機為 127.0.0.1:

$mysqli = new mysqli('127.0.0.1', 'user', 'pass', 'db', 3306);
$pdo = new PDO('mysql:host=127.0.0.1;dbname=db;port=3306', 'user', 'pass');

或全域配置 my.cnf 強制 TCP:

[mysqld]
protocol = TCP
skip-networking = 0
bind-address = 127.0.0.1

方案 3:建立 Socket 軟連結(快速修復)

ln -sf /var/run/mysqld/mysqld.sock /tmp/mysql.sock
# 或反向,視實際路徑而定

再設 mysqli.default_socket = /tmp/mysql.sock

方案 4:檢查 SELinux/AppArmor(常被忽略)

# 臨時關閉驗證
setenforce 0
# 或調整策略
ausearch -c 'php-fpm' --raw | audit2allow -M php-fpm-mysql
semodule -i php-fpm-mysql.pp

方案 5:Docker/容器環境專用

  • 容器間連接:使用服務名(mysql:3306)而非 localhost
  • 宿主機連接容器:映射端口 -p 3306:3306,用 127.0.0.1
  • 容器連接宿主機:host.docker.internal:3306 (Docker Desktop) 或宿主機真實 IP

驗證連接方式

<?php
$mysqli = new mysqli('localhost', 'root', 'pass', 'test');
if ($mysqli->connect_errno) {
    echo "失敗: " . $mysqli->connect_error;
} else {
    echo "成功,連接 ID: " . $mysqli->thread_id;
    echo "協議: " . $mysqli->protocol_version; // 10 = socket, 其他 = TCP
    $mysqli->close();
}
?>

最佳實踐總結

  1. 開發/生產環境統一用 127.0.0.1,避免 socket 路徑不一致問題,便於容器化遷移
  2. 若追求極致效能(單機高併發),配置正確 socket 路徑並使用 localhost
  3. PHP 代碼中顯式指定端口 3306,避免依賴預設值
  4. 監控連接錯誤率,設定告警(Prometheus + Grafana)

補充:Windows 平台無 Unix Socket,localhost 會自動解析為 TCP 連接,不存在此問題。跨平台部署時請注意此差異。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved