文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式 Letter) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  存取控制,階段 1:連線驗證

8.2.6 存取控制,階段 1:連線驗證

當您嘗試連線至 MySQL 伺服器時,伺服器會根據下列條件接受或拒絕連線

  • 您的身分以及您是否可以透過提供正確的認證來驗證它。

  • 您的帳戶是否已鎖定或解除鎖定。

伺服器會先檢查認證,然後檢查帳戶鎖定狀態。任何一個步驟失敗都會導致伺服器完全拒絕您的存取。否則,伺服器會接受連線,然後進入階段 2 並等待請求。

伺服器會使用 user 表格中的欄位執行身分和認證檢查,只有在符合下列條件時才會接受連線

  • 用戶端主機名稱和使用者名稱與某些 user 表格列中的 HostUser 欄位相符。有關允許的 HostUser 值的規則,請參閱第 8.2.4 節「指定帳戶名稱」

  • 用戶端會提供該列中指定的認證(例如,密碼),如 authentication_string 欄位所示。會使用 plugin 欄位中指定的驗證外掛程式來解譯認證。

  • 該列表示帳戶已解除鎖定。鎖定狀態會記錄在 account_locked 欄位中,該欄位的值必須為 'N'。可以使用 CREATE USERALTER USER 陳述式設定或變更帳戶鎖定。

您的身分基於兩個資訊

  • 您的 MySQL 使用者名稱。

  • 您連線的用戶端主機。

如果 User 欄位值不是空白,則傳入連線中的使用者名稱必須完全相符。如果 User 值為空白,則它會符合任何使用者名稱。如果符合傳入連線的 user 表格列具有空白的使用者名稱,則該使用者會被視為沒有名稱的匿名使用者,而不是具有用戶端實際指定名稱的使用者。這表示在連線期間(即在階段 2 期間),空白使用者名稱將用於所有進一步的存取檢查。

authentication_string 資料行可以為空白。這不是萬用字元,也不表示任何密碼都符合。它表示使用者必須在不指定密碼的情況下連線。驗證用戶端的插件所實作的驗證方法可能會使用或可能不會使用 authentication_string 資料行中的密碼。在這種情況下,也有可能使用外部密碼來驗證到 MySQL 伺服器。

儲存在 user 資料表的 authentication_string 資料行中的非空白密碼值會被加密。MySQL 不會將密碼以明文方式儲存供任何人查看。相反地,嘗試連線的使用者提供的密碼會被加密(使用帳戶驗證插件所實作的密碼雜湊方法)。然後,加密後的密碼會在連線過程中用於檢查密碼是否正確。這是在沒有加密密碼透過連線傳輸的情況下完成的。請參閱第 8.2.1 節「帳戶使用者名稱和密碼」

從 MySQL 伺服器的角度來看,加密後的密碼是真正的密碼,因此您絕對不應該讓任何人存取它。特別是,請勿讓非管理使用者讀取 mysql 系統資料庫中的表格

下表顯示 user 資料表中 UserHost 值的各種組合如何應用於傳入的連線。

User Host 允許的連線
'fred' 'h1.example.net' fred,從 h1.example.net 連線
'' 'h1.example.net' 任何使用者,從 h1.example.net 連線
'fred' '%' fred,從任何主機連線
'' '%' 任何使用者,從任何主機連線
'fred' '%.example.net' fred,從 example.net 網域中的任何主機連線
'fred' 'x.example.%' fred,從 x.example.netx.example.comx.example.edu 等等連線;這可能沒有用處
'fred' '198.51.100.177' fred,從 IP 位址為 198.51.100.177 的主機連線
'fred' '198.51.100.%' fred,從 198.51.100 C 類子網路中的任何主機連線
'fred' '198.51.100.0/255.255.255.0' 與前一個範例相同

傳入連線的用戶端主機名稱和使用者名稱可能符合 user 資料表中的多個資料列。前面的範例集示範了這一點:顯示的幾個條目都符合來自 h1.example.netfred 的連線。

當可能有多個匹配項時,伺服器必須決定使用哪個。它會按如下方式解決此問題

  • 每當伺服器將 user 資料表讀取到記憶體中時,它都會對資料列進行排序。

  • 當用戶端嘗試連線時,伺服器會依排序順序搜尋資料列。

  • 伺服器會使用第一個符合用戶端主機名稱和使用者名稱的資料列。

伺服器使用排序規則,將具有最特定 Host 值的資料列優先排序。

  • 常值 IP 位址和主機名稱是最特定的。

  • 主機部分具有 IP 位址的帳戶具有以下特定性順序

    • 主機部分以 IP 位址給出的帳戶

      CREATE USER 'user_name'@'127.0.0.1';
      CREATE USER 'user_name'@'198.51.100.44';
    • 主機部分以使用 CIDR 標記法的 IP 位址給出的帳戶

      CREATE USER 'user_name'@'192.0.2.21/8';
      CREATE USER 'user_name'@'198.51.100.44/16';
    • 主機部分以帶有子網路遮罩的 IP 位址給出的帳戶

      CREATE USER 'user_name'@'192.0.2.0/255.255.255.0';
      CREATE USER 'user_name'@'198.51.0.0/255.255.0.0';
  • 模式 '%' 表示 任何主機,並且是最不特定的。

  • 空字串 '' 也表示 任何主機,但在 '%' 之後排序。

非 TCP(socket 檔案、具名管道和共享記憶體)連線被視為本機連線,如果存在任何此類帳戶,則會符合 localhost 的主機部分,否則會符合帶有符合 localhost 的萬用字元的主機部分(例如,local%l%%)。

'%' 視為等同於 localhost 的處理方式已棄用;您應該預期此行為將從未來的 MySQL 版本中移除。

具有相同 Host 值的資料列會以最特定的 User 值優先排序。空白的 User 值表示 任何使用者,並且是最不特定的,因此對於具有相同 Host 值的資料列,非匿名使用者會排在匿名使用者之前。

對於具有相同特定性的 HostUser 值的資料列,順序是不確定的。

為了了解它是如何運作的,假設 user 資料表如下所示

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

當伺服器將資料表讀取到記憶體中時,它會使用剛才描述的規則對資料列進行排序。排序後的結果如下所示

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

當用戶端嘗試連線時,伺服器會搜尋排序後的資料列,並使用找到的第一個匹配項。對於 jeffreylocalhost 的連線,資料表中兩個資料列符合:一個是 HostUser 值為 'localhost''' 的資料列,另一個是值為 '%''jeffrey' 的資料列。'localhost' 資料列在排序後的順序中排在前面,因此伺服器使用該資料列。

以下是另一個範例。假設 user 資料表如下所示

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| h1.example.net |          | ...
+----------------+----------+-

排序後的資料表如下所示

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| h1.example.net |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

第一個資料列符合來自 h1.example.net 的任何使用者的連線,而第二個資料列符合來自任何主機的 jeffrey 的連線。

注意

一個常見的誤解是認為,對於給定的使用者名稱,當伺服器嘗試為連線尋找匹配項時,會首先使用所有明確命名該使用者的資料列。事實並非如此。前面的範例說明了這一點,其中來自 h1.example.netjeffrey 的連線首先不是由 User 資料行值包含 'jeffrey' 的資料列匹配,而是由沒有使用者名稱的資料列匹配。因此,jeffrey 會被驗證為匿名使用者,即使他在連線時指定了使用者名稱。

如果您可以連線到伺服器,但您的權限與您預期的不符,您可能正在被驗證為其他帳戶。若要找出伺服器用來驗證您的帳戶,請使用 CURRENT_USER() 函數。(請參閱第 14.15 節「資訊函數」。)它會以 user_name@host_name 格式傳回一個值,該值指示匹配的 user 資料表資料列中的 UserHost 值。假設 jeffrey 連線並發出以下查詢

mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

此處顯示的結果表示匹配的 user 資料表資料列具有空白的 User 資料行值。換句話說,伺服器將 jeffrey 視為匿名使用者。

診斷驗證問題的另一種方法是列印出 user 資料表並手動排序,以查看第一個匹配項是在哪裡建立的。