一、現象
在生產環境中我們偶爾會遇到show processlist;顯示host為 unauthenticated user 這樣的連接,同時伴有數據庫服務器層面的load,sys cpu較高,或者thread running異常。
二、分析
類似於校園門衛看到一個陌生的人進入學校,對TA提出的哲學式問題:TA是誰?從哪里來? 要干什么?本文從IT技術角度回答這個哲學問題。
TA是誰?
官方介紹:
unauthenticated user refers to a thread that has become associated with a client connection but for which authentication of the client user has not yet been done。
意即:MySQL有一個線程在處理客戶端的連接,但是該客戶端還沒通過用戶驗證,show processlist時顯示"unauthenticated user"。
從哪里來?
回答這個問題之前,我們先了解client端和MySQL建立TCP連接(socket不在討論范圍之內)的過程,一般客戶端建立與MySQL的連接分4步:
-
客戶端發送數據包到MySQL服務器,准備建立連接。如果MySQL服務器對應的端口沒有運行,則客戶端會直接收到報錯信息:
ERROR 2003 (HY000): Can't connect to MySQL server on '[host]' (111)
-
MySQL服務器向客戶端響應基本信息 數據庫服務器的ip,port,mysqld version,the thread id,客戶端的host,port等等,此時連接已經建立但是尚未完成授權。
“When a new client connects to mysqld, mysqld spawns a new thread to handle the request. This thread first checks whether the host name is in the host name cache. If not, the thread attempts to resolve the host name: The thread takes the IP address and resolves it to a host name (using gethostbyaddr()). It then takes that host name and resolves it back to the IP address (using gethostbyname()) and compares to ensure it is the original IP address.”
實際連接過程是 mysql 分配一個新的線程來處理客戶端的連接請求。先檢查客戶端的hostname 是否在緩存中,如果不在則對hostname解析。先作反向解析客戶端IP --> 客戶端的hostname,然后作客戶端的hostname --> 客戶端IP的正向解析。如果結果符合,則驗證為合法用戶允許登錄,如果不符合則定義為"unauthenticated user"。
- 客戶端發送username/password/要訪問的dbname到MySQ數據庫服務器。如果客戶端由於某些原因在connect_timeout規定的時間內沒有發送包或者發送錯誤的包,數據庫服務器會斷開該連接。
- 服務器驗證並返回驗證結果給客戶端。如果驗證不通過 則通常返回:
ERROR 1045 (28000): Access denied for user 'user'@'host' (using password: [YES/NO])
要做什么?
顯然此類連接是要訪問數據庫,准備獲取數據或者寫入數據。但是我們如何規避這樣的三無人員的出現呢? 從該問題產生的原因來分析,主要的解決方法如下:-
在 /etc/my.cnf 的[mysqld]中添加
skip-name-resolve
參數,關閉mysql的dns反查詢,mysql使用IP或者%授權。
-
在 /etc/hosts 添加IP與主機名對應關系
192.168.0.1 xxxx
目標機器上 MySQL中執行telnet x.x.x.x 3306
有一個連接顯示為unauthenticated user 。 因此這種現象不一定就是數據庫本身的問題,下面這些都有可能產生這種現象:mysql>show processlist;
- 如果由於應用安全問題出現大量數據庫探測,出現大量這種未經授權的連接。
- 應用服務壓力過大出現線程異常中斷導致出現大量異常數據庫連接。
- 應用服務到db服務器的網絡異常,客戶端由於某些參數配置不正確致使正常的請求沒有在規定時間內發出,MySQL無法驗證連接的有效性。
- MySQL客戶端連接版本問題,驗證協議不兼容,尤其注意old-password驗證方式。
- 數據庫服務器的線程處於排隊狀態,因此可以加大back_log,增加MySQL處理連接請求的能力。
前三種情況要從應用服務器端查看系統的負載或者應用程序的狀態,后面兩個要從數據庫服務器層面來檢查系統的狀態。