天天看點

記一次MySQL資料庫拒絕通路的解決過程

記一次MySQL資料庫拒絕通路的解決過程

最近在折騰wordpress部落格,連接配接MySQL資料庫時提示拒絕通路。經過排查,解決了問題。這裡記錄下解決問題的方案,以及解決的思路。如有遇到類似問題的讀者可以參考下。

用wordpress搭部落格,資料庫采用MySQL。為了調試友善,建立賬戶

my_account

,允許它從任意主機通路資料庫。

CREATE USER `my_account`@'%' IDENTIFIED BY 'my_password';
           
Copy

修改 wp-config.php 相應配置,注意

DB_HOST

設定為

127.0.0.1

define('DB_USER', 'my_account'); // 賬号
define('DB_PASSWORD', 'my_password'); // 密碼
define('DB_HOST', '127.0.0.1'); // 資料服務位址
           

部署到雲伺服器上,本地浏覽器通路部落格,提示資料庫拒絕通路(本地連接配接遠端資料沒問題),以下為錯誤日志。

ERROR 1045 (28000): Access denied for user 'my_account'@'localhost' (using password: YES)`
           

簡單排查後,解決了問題,這裡記錄下解決方案,以及出錯的原因。

解決方案

1、方案一:删除 mysql.user表 中,Host字段為 localhost 的匿名賬号(賬戶名為空)。

2、方案二:建立 my_account@localhost 賬戶,用于本地連接配接資料庫。

筆者采用了方案 一。

首先,确認下 mysql.user 表中是否存在匿名賬戶。

MariaDB [(none)]> SELECT User, Host from mysql.user WHERE Host = 'localhost' AND User = '';
+------+-----------+
| User | Host      |
+------+-----------+
|      | localhost |
+------+-----------+
1 row in set (0.00 sec)
           

接着,删除相應匿名賬戶,再次嘗試登陸,成功。

MariaDB [(none)]> DROP USER ''@'localhost';
Query OK, 0 rows affected (0.00 sec)
           

問題分析

為什麼匿名賬戶會導緻資料庫連接配接失敗?

需要對MySQL的賬戶建立、用戶端連接配接校驗有一定的了解。

建立MySQL賬戶

基礎文法如下:

CREATE USER 賬戶名@主機 IDENTIFIED BY 密碼;
           

注意點:(以下用 User 指代賬戶名,Host 指代 主機)

  1. Host 表示 允許賬戶從哪台主機通路資料庫。主要用于做安全限制,可以是 主機名、IP位址、%(通配符);
  2. User 允許重複,隻要 Host 是不同的就行。
  3. 當 Host 設定為 % 時,表示允許從任意主機連接配接資料庫。

比如,存在兩個xiaoming賬戶,一個允許從本機連接配接資料庫,一個允許從 14.215.177.39 連接配接資料庫。

MariaDB [(none)]> SELECT User, Host FROM mysql.user WHERE User = 'xiaoming';           
+---------+---------------+
| User    | Host          |
+---------+---------------+
| xiaoming | 14.215.177.39 |
| xiaoming | localhost     |
+---------+---------------+
2 rows in set (0.00 sec)
           

匿名賬戶

也就是 User 為空的賬戶,可以比對任意使用者名。如下指令建立了匿名賬戶。

CREATE USER ''@'localhost' IDENTIFIED BY 'pwd3';
           

身份校驗

資料庫伺服器收到用戶端連接配接,首先會進行身份校驗,将 User、Host、Password 字段,跟 mysql.user 表裡的記錄進行比較,确認是否合法賬戶。

這裡有個問題:如果 mysql.user表 中存在多條比對記錄,該以哪條記錄為準?

答案是“優先級”。大緻規則如下:

  1. 首先,檢查 Host 字段。如果有多個 Host 符合條件,則選擇比對度最高的記錄(IP位址 > 通配符%)。
  2. 其次,檢查 User 字段。如果有多個 User 符合條件,則選擇比對度最高的記錄。匿名使用者可以比對任何使用者,是以比對度最低。

優先級比對例子

舉例,假設本地資料庫有如下兩個賬戶(Password字段實際非明文)。

+------------+-----------+-----------+
| User       | Host      | Password  |
+------------+-----------+-----------+
| my_account | %         | 123       |
|            | localhost | 456       |
+------------+-----------+-----------+
           

運作如下指令,最終登入的賬戶,比對的是 第2條 記錄。(讀者可自行嘗試,輸入密碼123登入失敗,輸入456登入成功)

mysql -u my_account -p
           

為什麼呢?回顧下比對的優先級。

  1. 首先,檢查 Host 字段。localhost、% 都符合要求。localhost 比對度高于 %,是以比對到第2條記錄。
  2. 接着,檢查 User 字段。第2條記錄是匿名賬戶,可比對任意User值,是以,第2條記錄符合要求。

是以,雖然賬戶 my_account 的 Host字段 為%,但是在本地(資料庫所在主機)連接配接資料庫時,因為上述規則的存在,MySQL 會認為你是用匿名賬戶在登入。

my_account 跟匿名賬戶的密碼是不同的,是以密碼校驗不通過,拒絕通路。

寫在後面

因匿名使用者存在,導緻本地連接配接資料庫拒絕連接配接,這個問題很常見,有不少人認為這是MySQL的設計缺陷,比如

這裡

了解了MySQL的身份驗證邏輯,遇到類似問題也就有思路了。關于%通配符,比對優先級,上文并沒有詳細展開,感興趣的讀者可以自行檢視官方文檔。

另外,MySQL拒絕通路的原因有多種,讀者應具體問題具體分析。

如有錯漏,敬請指出。