mysql
系統資料庫包含數個授權表,其中包含使用者帳戶及其所持有的權限相關資訊。本節說明這些表格。如需系統資料庫中其他表格的相關資訊,請參閱第 7.3 節「mysql 系統結構描述」。
此處的討論說明授權表的基礎結構,以及伺服器在與用戶端互動時如何使用其內容。不過,通常您不會直接修改授權表。當您使用諸如 CREATE USER
、GRANT
和 REVOKE
等帳戶管理陳述式來設定帳戶和控制每個帳戶可用的權限時,會間接發生修改。請參閱第 15.7.1 節「帳戶管理陳述式」。當您使用此類陳述式執行帳戶操作時,伺服器會代表您修改授權表。
不建議使用諸如 INSERT
、UPDATE
或 DELETE
等陳述式直接修改授權表,且風險由您自行承擔。伺服器可以自由忽略由於此類修改而變得格式錯誤的資料列。
對於任何修改授權表的操作,伺服器都會檢查表格是否具有預期的結構,如果沒有,則會產生錯誤。若要將表格更新為預期的結構,請執行 MySQL 升級程序。請參閱第 3 章升級 MySQL。
這些 mysql
資料庫表格包含授權資訊
user
:使用者帳戶、靜態全域權限和其他非權限欄。global_grants
:動態全域權限。db
:資料庫層級權限。tables_priv
:資料表層級權限。columns_priv
:欄位層級權限。procs_priv
:預存程序和函式權限。proxies_priv
:代理使用者權限。default_roles
:預設使用者角色。role_edges
:角色子圖的邊。password_history
:密碼變更歷史紀錄。
有關靜態和動態全域權限之間差異的資訊,請參閱靜態與動態權限。)
在 MySQL 8.4 中,授權表使用 InnoDB
儲存引擎並且是事務性的。在 MySQL 8.4 之前,授權表使用 MyISAM
儲存引擎並且是非事務性的。授權表儲存引擎的此項變更使得帳戶管理語句(例如 CREATE USER
或 GRANT
)的行為也隨之改變。以前,為多個使用者命名的帳戶管理語句可能對某些使用者成功,而對其他使用者失敗。現在,每個語句都是事務性的,如果發生任何錯誤,則要麼對所有命名的使用者都成功,要麼回滾且沒有任何影響。
每個授權表都包含範圍欄位和權限欄位
範圍欄位決定表中每列的範圍;也就是說,該列適用的上下文。例如,具有
Host
和User
值分別為'h1.example.net'
和'bob'
的user
表列適用於從主機h1.example.net
連接到伺服器的驗證連線,該用戶端指定的使用者名稱為bob
。同樣地,當bob
從主機h1.example.net
連線以存取reports
資料庫時,具有Host
、User
和Db
欄位值分別為'h1.example.net'
、'bob'
和'reports'
的db
表列適用。tables_priv
和columns_priv
表包含指示每列適用的資料表或資料表/欄位組合的範圍欄位。procs_priv
範圍欄位指示每列適用的預存程序。權限欄位指示資料表列授予哪些權限;也就是說,它允許執行哪些操作。伺服器結合各個授權表中的資訊,以形成使用者權限的完整描述。 第 8.2.7 節,「存取控制,階段 2:請求驗證」描述了相關規則。
此外,授權表可能包含用於範圍或權限評估以外目的的欄位。
伺服器以下列方式使用授權表
user
表範圍欄位決定是否拒絕或允許連入連線。對於允許的連線,user
表中授予的任何權限都表示使用者的靜態全域權限。在此表中授予的任何權限都適用於伺服器上的所有資料庫。注意由於任何靜態全域權限都被視為所有資料庫的權限,因此任何靜態全域權限都允許使用者透過
SHOW DATABASES
或檢查INFORMATION_SCHEMA
的SCHEMATA
表來檢視所有資料庫名稱,除非資料庫已透過部分撤銷在資料庫層級受到限制。global_grants
表列出目前分配給使用者帳戶的動態全域權限。對於每列,範圍欄位決定哪個使用者擁有權限欄位中命名的權限。db
表範圍欄位決定哪些使用者可以從哪些主機存取哪些資料庫。權限欄位決定允許的操作。在資料庫層級授予的權限適用於資料庫以及資料庫中的所有物件,例如資料表和預存程式。tables_priv
和columns_priv
表與db
表類似,但更精細:它們適用於資料表和欄位層級,而不是資料庫層級。在資料表層級授予的權限適用於資料表及其所有欄位。在欄位層級授予的權限僅適用於特定欄位。procs_priv
表適用於預存常式(預存程序和函式)。在常式層級授予的權限僅適用於單一程序或函式。proxies_priv
表指示哪些使用者可以充當其他使用者的代理,以及使用者是否可以將PROXY
權限授予其他使用者。default_roles
和role_edges
表包含有關角色關係的資訊。password_history
表保留先前選擇的密碼,以便限制密碼重複使用。請參閱第 8.2.15 節,「密碼管理」。
伺服器會在啟動時將授權表的內容讀取到記憶體中。您可以透過發出 FLUSH PRIVILEGES
語句或執行 mysqladmin flush-privileges 或 mysqladmin reload 命令來告知伺服器重新載入這些表。對授權表的變更會依據第 8.2.13 節,「權限變更生效的時間」中指示的方式生效。
當您修改帳戶時,最好驗證您的變更是否具有預期的效果。若要檢查給定帳戶的權限,請使用 SHOW GRANTS
語句。例如,若要判斷授予使用者名稱和主機名稱值分別為 bob
和 pc84.example.com
的帳戶的權限,請使用此語句
SHOW GRANTS FOR 'bob'@'pc84.example.com';
若要顯示帳戶的非權限屬性,請使用 SHOW CREATE USER
SHOW CREATE USER 'bob'@'pc84.example.com';
伺服器會在存取控制的第一階段和第二階段(請參閱第 8.2 節,「存取控制和帳戶管理」)使用 mysql
資料庫中的 user
和 db
表。此處顯示 user
和 db
表中的欄位。
表 8.4 user 和 db 資料表欄位
資料表名稱 | user |
db |
---|---|---|
範圍欄位 | Host |
Host |
User |
Db |
|
User |
||
權限欄位 | Select_priv |
Select_priv |
Insert_priv |
Insert_priv |
|
Update_priv |
Update_priv |
|
Delete_priv |
Delete_priv |
|
Index_priv |
Index_priv |
|
Alter_priv |
Alter_priv |
|
Create_priv |
Create_priv |
|
Drop_priv |
Drop_priv |
|
Grant_priv |
Grant_priv |
|
Create_view_priv |
Create_view_priv |
|
Show_view_priv |
Show_view_priv |
|
Create_routine_priv |
Create_routine_priv |
|
Alter_routine_priv |
Alter_routine_priv |
|
Execute_priv |
Execute_priv |
|
Trigger_priv |
Trigger_priv |
|
Event_priv |
Event_priv |
|
Create_tmp_table_priv |
Create_tmp_table_priv |
|
Lock_tables_priv |
Lock_tables_priv |
|
References_priv |
References_priv |
|
Reload_priv |
||
Shutdown_priv |
||
Process_priv |
||
File_priv |
||
Show_db_priv |
||
Super_priv |
||
Repl_slave_priv |
||
Repl_client_priv |
||
Create_user_priv |
||
Create_tablespace_priv |
||
Create_role_priv |
||
Drop_role_priv |
||
安全性欄位 | ssl_type |
|
ssl_cipher |
||
x509_issuer |
||
x509_subject |
||
plugin |
||
authentication_string |
||
password_expired |
||
password_last_changed |
||
password_lifetime |
||
account_locked |
||
Password_reuse_history |
||
Password_reuse_time |
||
Password_require_current |
||
User_attributes |
||
資源控制欄位 | max_questions |
|
max_updates |
||
max_connections |
||
max_user_connections |
user
資料表的 plugin
和 authentication_string
欄位儲存驗證外掛程式和認證資訊。
伺服器會使用帳戶列的 plugin
欄位中命名的外掛程式來驗證該帳戶的連線嘗試。
plugin
欄位不得為空。在啟動時,以及在執行 FLUSH PRIVILEGES
時的執行時間,伺服器會檢查 user
資料表列。對於任何 plugin
欄位為空的列,伺服器會將此表單的警告寫入錯誤日誌
[Warning] User entry 'user_name'@'host_name' has an empty plugin
value. The user will be ignored and no one can login with this user
anymore.
若要將外掛程式指派給缺少外掛程式的帳戶,請使用 ALTER USER
語句。
password_expired
欄位允許資料庫管理員 (DBA) 使帳戶密碼過期,並要求使用者重設密碼。預設的 password_expired
值為 'N'
,但可以使用 ALTER USER
陳述式將其設定為 'Y'
。在帳戶的密碼過期後,該帳戶在後續連線到伺服器時執行的所有操作都會導致錯誤,直到使用者發出 ALTER USER
陳述式以建立新的帳戶密碼。
雖然可以透過將過期的密碼設定為其目前的值來「「重設」」,但作為良好的策略,最好選擇不同的密碼。資料庫管理員可以透過建立適當的密碼重複使用原則來強制禁止重複使用。請參閱密碼重複使用原則。
password_last_changed
是一個 TIMESTAMP
欄位,指示上次變更密碼的時間。該值僅對使用 MySQL 內建驗證外掛程式 (mysql_native_password
,已棄用、sha256_password
,已棄用,或 caching_sha2_password
) 的帳戶為非 NULL
。對於其他帳戶,例如使用外部驗證系統進行驗證的帳戶,該值為 NULL
。
password_last_changed
會由 CREATE USER
、ALTER USER
和 SET PASSWORD
陳述式,以及建立帳戶或變更帳戶密碼的 GRANT
陳述式更新。
password_lifetime
表示帳戶密碼的有效期限,以天為單位。如果密碼超過其有效期限 (使用 password_last_changed
欄位評估),則當用戶端使用該帳戶連線時,伺服器會認為密碼已過期。大於零的 N
值表示密碼必須每 N
天變更一次。值為 0 會停用自動密碼過期。如果值為 NULL
(預設值),則會套用全域過期原則,如 default_password_lifetime
系統變數所定義。
account_locked
表示帳戶是否已鎖定 (請參閱第 8.2.20 節「帳戶鎖定」)。
Password_reuse_history
是帳戶的 PASSWORD HISTORY
選項的值,或預設歷史記錄的 NULL
。
Password_reuse_time
是帳戶的 PASSWORD REUSE INTERVAL
選項的值,或預設間隔的 NULL
。
Password_require_current
對應於帳戶的 PASSWORD REQUIRE
選項的值,如下表所示。
表 8.5:允許的 Password_require_current 值
Password_require_current 值 | 對應的 PASSWORD REQUIRE 選項 |
---|---|
'Y' |
PASSWORD REQUIRE CURRENT |
'N' |
PASSWORD REQUIRE CURRENT OPTIONAL |
NULL |
PASSWORD REQUIRE CURRENT DEFAULT |
User_attributes
是一個 JSON 格式的欄位,用於儲存未儲存在其他欄位中的帳戶屬性。INFORMATION_SCHEMA
通過 USER_ATTRIBUTES
表格公開這些屬性。
User_attributes
欄位可能包含以下屬性
additional_password
:次要密碼 (如果有的話)。請參閱雙重密碼支援。Restrictions
:限制清單 (如果有的話)。限制由部分撤銷操作新增。屬性值是一個元素陣列,每個元素都有Database
和Restrictions
鍵,指示受限制的資料庫名稱和適用於該資料庫的限制 (請參閱第 8.2.12 節「使用部分撤銷的權限限制」)。Password_locking
:失敗登入追蹤和暫時帳戶鎖定的條件 (如果有的話) (請參閱失敗登入追蹤和暫時帳戶鎖定)。Password_locking
屬性會根據CREATE USER
和ALTER USER
陳述式的FAILED_LOGIN_ATTEMPTS
和PASSWORD_LOCK_TIME
選項進行更新。屬性值是一個雜湊,其中包含failed_login_attempts
和password_lock_time_days
鍵,指示為帳戶指定的選項值。如果缺少某個鍵,則其值隱含為 0。如果鍵值隱含或明確為 0,則會停用對應的功能。multi_factor_authentication
:mysql.user
系統表格中的列有一個plugin
欄位,指示驗證外掛程式。對於單因素驗證,該外掛程式是唯一的驗證因素。對於雙因素或三因素形式的多因素驗證,該外掛程式對應於第一個驗證因素,但必須儲存其他資訊以用於第二個和第三個因素。multi_factor_authentication
屬性會保留此資訊。multi_factor_authentication
值是一個陣列,其中每個陣列元素都是一個雜湊,使用以下屬性描述一個驗證因素plugin
:驗證外掛程式的名稱。authentication_string
:驗證字串值。passwordless
:一個旗標,表示使用者是否打算在沒有密碼的情況下使用 (僅使用安全令牌作為驗證方法)。requires_registration
:一個旗標,定義使用者帳戶是否已註冊安全令牌。
第一個和第二個陣列元素描述多因素驗證因素 2 和 3。
如果沒有適用屬性,則 User_attributes
為 NULL
。
範例:具有次要密碼和部分撤銷資料庫權限的帳戶,其欄位值中包含 additional_password
和 Restrictions
屬性
mysql> SELECT User_attributes FROM mysql.User WHERE User = 'u'\G
*************************** 1. row ***************************
User_attributes: {"Restrictions":
[{"Database": "mysql", "Privileges": ["SELECT"]}],
"additional_password": "hashed_credentials"}
若要判斷存在哪些屬性,請使用 JSON_KEYS()
函數
SELECT User, Host, JSON_KEYS(User_attributes)
FROM mysql.user WHERE User_attributes IS NOT NULL;
若要提取特定屬性,例如 Restrictions
,請執行以下操作
SELECT User, Host, User_attributes->>'$.Restrictions'
FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
以下是為 multi_factor_authentication
儲存的資訊範例
{
"multi_factor_authentication": [
{
"plugin": "authentication_ldap_simple",
"passwordless": 0,
"authentication_string": "ldap auth string",
"requires_registration": 0
},
{
"plugin": "authentication_webauthn",
"passwordless": 0,
"authentication_string": "",
"requires_registration": 1
}
]
}
在存取控制的第二階段,伺服器會執行請求驗證,以確保每個用戶端對於其發出的每個請求都具有足夠的權限。除了 user
和 db
授權表格之外,伺服器可能還會針對涉及表格的請求查詢 tables_priv
和 columns_priv
表格。後面的表格在表格和欄位層級提供更精細的權限控制。它們具有下表中顯示的欄位。
表 8.6:tables_priv 和 columns_priv 表格欄位
資料表名稱 | tables_priv |
columns_priv |
---|---|---|
範圍欄位 | Host |
Host |
Db |
Db |
|
User |
User |
|
Table_name |
Table_name |
|
Column_name |
||
權限欄位 | Table_priv |
Column_priv |
Column_priv |
||
其他欄位 | Timestamp |
Timestamp |
Grantor |
Timestamp
和 Grantor
欄位分別設定為目前的時間戳記和 CURRENT_USER
值,但其他情況下未使用。
對於涉及儲存常式的請求驗證,伺服器可能會查詢 procs_priv
表格,該表格具有下表中顯示的欄位。
表 8.7:procs_priv 表格欄位
資料表名稱 | procs_priv |
---|---|
範圍欄位 | Host |
Db |
|
User |
|
Routine_name |
|
Routine_type |
|
權限欄位 | Proc_priv |
其他欄位 | Timestamp |
Grantor |
Routine_type
欄位是一個 ENUM
欄位,其值為 'FUNCTION'
或 'PROCEDURE'
,表示列所參考的常式類型。此欄位允許針對具有相同名稱的函式和程序分別授予權限。
Timestamp
和 Grantor
欄位未使用。
proxies_priv
表格記錄有關 Proxy 帳戶的資訊。它具有以下欄位
若要讓帳戶能夠將 PROXY
權限授予其他帳戶,它必須在 proxies_priv
表格中有一列,其中 With_grant
設定為 1,且 Proxied_host
和 Proxied_user
設定為指出可以授予權限的帳戶或帳戶群。例如,在 MySQL 安裝期間建立的 'root'@'localhost'
帳戶在 proxies_priv
表格中有一列,可啟用對 ''@''
(也就是所有使用者和所有主機) 授予 PROXY
權限。這使得 root
能夠設定代理使用者,以及將設定代理使用者的權限委派給其他帳戶。請參閱 第 8.2.19 節「代理使用者」。
global_grants
表格列出目前指派給使用者帳戶的動態全域權限。此表格包含以下欄位:
USER
,HOST
:獲授予權限的帳戶的使用者名稱和主機名稱。PRIV
:權限名稱。WITH_GRANT_OPTION
:該帳戶是否可以將權限授予其他帳戶。
default_roles
表格列出預設使用者角色。此表格包含以下欄位:
HOST
,USER
:預設角色適用於的帳戶或角色。DEFAULT_ROLE_HOST
,DEFAULT_ROLE_USER
:預設角色。
role_edges
表格列出角色子圖的邊緣。此表格包含以下欄位:
FROM_HOST
,FROM_USER
:被授予角色的帳戶。TO_HOST
,TO_USER
:授予帳戶的角色。WITH_ADMIN_OPTION
:該帳戶是否可以使用WITH ADMIN OPTION
將角色授予其他帳戶以及從其他帳戶撤銷角色。
password_history
表格包含關於密碼變更的資訊。此表格包含以下欄位:
Host
,User
:發生密碼變更的帳戶。Password_timestamp
:密碼變更發生的時間。Password
:新的密碼雜湊值。
password_history
表格會累積每個帳戶足夠數量的非空密碼,以使 MySQL 能夠針對帳戶密碼歷程記錄長度和重複使用間隔執行檢查。當密碼變更嘗試發生時,會自動修剪超出這兩個限制的項目。
空密碼不會計入密碼歷程記錄中,並且隨時可以重複使用。
如果帳戶被重新命名,其項目會重新命名以匹配。如果帳戶被刪除或其身份驗證外掛程式被變更,其項目將被移除。
授權表格中的範圍欄位包含字串。每個欄位的預設值為空字串。下表顯示每個欄位中允許的字元數。
表格 8.8:授權表格範圍欄位長度
欄位名稱 | 允許的最大字元數 |
---|---|
Host , Proxied_host |
255 |
User , Proxied_user |
32 |
Db |
64 |
Table_name |
64 |
Column_name |
64 |
Routine_name |
64 |
Host
和 Proxied_host
值在儲存在授權表格之前會轉換為小寫。
為了進行存取檢查,User
、Proxied_user
、authentication_string
、Db
和 Table_name
值的比較會區分大小寫。Host
、Proxied_host
、Column_name
和 Routine_name
值的比較不區分大小寫。
user
和 db
表格在單獨的欄位中列出每個權限,該欄位宣告為 ENUM('N','Y') DEFAULT 'N'
。換句話說,每個權限都可以停用或啟用,預設為停用。
tables_priv
、columns_priv
和 procs_priv
表格將權限欄位宣告為 SET
欄位。這些欄位中的值可以包含表格控制的權限的任何組合。只有欄位值中列出的權限才會啟用。
表格 8.9:設定型別權限欄位值
資料表名稱 | 欄位名稱 | 可能的設定元素 |
---|---|---|
tables_priv |
Table_priv |
'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter', 'Create View', 'Show view', 'Trigger' |
tables_priv |
Column_priv |
'Select', 'Insert', 'Update', 'References' |
columns_priv |
Column_priv |
'Select', 'Insert', 'Update', 'References' |
procs_priv |
Proc_priv |
'Execute', 'Alter Routine', 'Grant' |
只有 user
和 global_grants
表格會指定管理權限,例如 RELOAD
、SHUTDOWN
和 SYSTEM_VARIABLES_ADMIN
。管理操作是對伺服器本身的操作,而非特定於資料庫,因此沒有理由在其他授權表格中列出這些權限。因此,伺服器只需要查詢 user
和 global_grants
表格,以判斷使用者是否可以執行管理操作。
FILE
權限也只在 user
表格中指定。它本身不是管理權限,但使用者在伺服器主機上讀取或寫入檔案的能力與所存取的資料庫無關。
為了允許在 MySQL 授權表格上進行並行的 DML 和 DDL 操作,先前在 MySQL 授權表格上獲取列鎖定的讀取操作會以非鎖定讀取的方式執行。在 MySQL 授權表格上執行為非鎖定讀取的操作包括:
SELECT
陳述式和其他唯讀陳述式,這些陳述式透過聯結列表和子查詢從授權表格讀取資料,包括SELECT ... FOR SHARE
陳述式,使用任何交易隔離等級。使用任何交易隔離等級,從授權表格讀取資料(透過聯結列表或子查詢)但不修改它們的 DML 操作。
在從授權表格讀取資料時不再獲取列鎖定的陳述式,如果在執行時使用基於陳述式的複寫,則會報告警告。
當使用 -binlog_format=mixed
時,從授權表格讀取資料的 DML 操作會以資料列事件的形式寫入二進位記錄檔,以使操作對於混合模式複寫是安全的。
從授權表格讀取資料的 SELECT ... FOR SHARE
陳述式會報告警告。對於 FOR SHARE
子句,授權表格不支援讀取鎖定。
讀取授權表格資料並使用 SERIALIZABLE
隔離等級執行的 DML 操作會報告警告。使用 SERIALIZABLE
隔離等級時通常會獲取的讀取鎖定在授權表格上不受支援。