MariaDB/MySQL中的user由用戶名和主機名構成,如"root@localhost",同用戶名但不一樣主機名對MySQL/MariaDB來說是不一樣的,也就是說"root@localhost"和"root@127.0.0.1"是不一樣的用戶,儘管它們都是本機的root。mysql
在MariaDB/MySQL服務器啓動後會載入權限表到內存中,當用戶要鏈接服務器,會讀取權限表來驗證和分配權限,即在內存中進行權限的讀取和寫入。sql
MariaDB/MySQL中的權限系統通過兩步驗證:數據庫
1.合法性驗證:驗證user是否合法,合法者容許鏈接服務器,不然拒絕鏈接。安全
2.權限驗證和分配:對經過合法性驗證的用戶分配對數據庫中各對象的操做權限。服務器
MariaDB/MySQL中的權限表都存放在mysql數據庫中。MySQL5.6之前,權限相關的表有user表、db表、host表、tables_priv表、columns_priv表、procs_priv表(存儲過程和函數相關的權限)。從MySQL5.6開始,host表已經沒有了。MariaDB中雖然有host表,但卻不用。網絡
這幾個表用的最多的是user表。user表主要分爲幾個部分:用戶列、權限列、安全列、資源控制列以及雜項列,最須要關注的是用戶列和權限列。其中權限列又分爲普通權限(上表中紅色字體)和管理權限列,如select類的爲普通權限,super權限爲管理權限。且能夠看到,db表中的權限全都是普通權限,user表中除了db表中具備的普通權限還有show_db_pirv和create_tablespace_priv,除此以外還有幾個管理員權限。也就是說,db中沒有的權限是沒法授予到指定數據庫的。例如不能授予super權限給test數據庫。ide
另外,usage權限在上表中沒有列出,由於該權限是全部用戶都有的權限,它只用來表示可否登陸數據庫,它的一個特殊功能是grant僅指定該權限的時候不會影響現有權限,也就是說能夠拿grant來修改密碼而不影響現有權限。函數
須要說明的是,從user表到db表再到tables_priv表最後是columns_priv表,它們的權限是逐層細化的。user表中的普通權限是針對全部數據庫的,例如在user表中的select_priv爲Y,則對全部數據庫都有select權限;db表是針對特定數據庫中全部表的,若是隻有test數據庫中有select權限,那麼db表中就有一條記錄test數據庫的select權限爲Y,這樣對test數據庫中的全部表都有select權限,而此時user表中的select權限就爲N(由於爲Y的時候是全部數據庫都有權限);同理tables_priv表也同樣,是針對特定表中全部列的權限;columns_priv則是針對特定列的權限。字體
因此對於已經經過身份合法性驗證的用戶的權限讀取和分配的機制以下:spa
例如,爲某一用戶授予test數據庫的select權限。能夠看到user表中的select_priv爲N,而db表中的select爲Y。
GRANT SELECT ON test.* TO 'long'@'192.168.100.1' IDENTIFIED BY '123456'; SELECT host,user,select_priv FROM mysql.user; SELECT * FROM mysql.db;
在服務器啓動時讀取權限表到內存中,今後時開始權限表生效。
以後使用grant、revoke、set password 等命令也會隱含的刷新權限表到內存中。
另外,使用顯式的命令flush privileges或mysqladmin flush-privileges或mysqladmin reolad也會將上述幾張權限表從新刷到內存中以供後續的身份驗證和權限驗證、分配。
用戶管理分爲幾個方面,建立用戶、對用戶受權、修改和刪除用戶。
建立帳號有幾種方法。
後兩種方法建立的用戶初始時沒有任何權限(只有usage登陸數據庫的權限),而且修改權限後要使用 FLUSH PRIVILEGES 語句或執行 mysqladmin flush-privileges 或 mysqladmin reload 命令刷新權限表到內存中,而第一種方法簡便的多,建立用戶後會自動刷新權限表。
grant和revoke語法:
GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level TO user [IDENTIFIED [BY [PASSWORD] 'password'][WITH with_option [with_option] object_type: TABLE | FUNCTION | PROCEDURE priv_level: * | *.* | db_name.* | db_name.tbl_name | tbl_name | db_name.routine_name with_option: GRANT OPTION | MAX_QUERIES_PER_HOUR count | MAX_UPDATES_PER_HOUR count | MAX_CONNECTIONS_PER_HOUR count | MAX_USER_CONNECTIONS count | MAX_STATEMENT_TIME time
grant能夠在庫、表、函數、存儲過程、特定列上受權,且一次性能夠爲多個用戶授予多個對象的權限。其中 with grant option 表示擁有該權限後的用戶能夠給別的用戶授予自身所擁有的權限。
revoke表示收回權限,注意revoke沒法收回usage權限。
其中user的表示方法是 '用戶名'@'主機名' ,主機名部分能夠是主機名,能夠是IP地址,能夠是localhost,能夠是通配符組成的主機名(空的host值也表示全部host,等價於'user_name'@'%')。以下示例:
對於網段地址,能夠指定掩碼來表示,如192.168.100.1/255.255.255.0,不能使用cidr格式的掩碼記錄方式,也不能指定非八、1六、2四、32位的掩碼,如192.168.100.1/255.255.255.240是不容許的。
若是在user表中的用戶有交叉部分,如root既能夠從localhost登陸,也能夠從127.0.0.1登陸,還能夠從本機IP192.168.100.61登陸,還能夠從網段地址192.168.100.%登陸,那麼到底會從哪一個登陸?
在讀取權限表user到內存中的時候,首先會根據host列的具體性進行排序,而後再根據user列進行具體性排序(即理解爲order by host,user),而後從上到下掃描,首次掃描到符合的記錄就使用該記錄登陸。具體性的意思是越具體的user優先級越高,通配符範圍越寬的user優先級越低。例如root@localhost的具體性比root@'%'的具體性高,後者又比'%'@'%'的具體性高。
在MySQL 5.6.7以前,不要使用這兩個命令建立用戶和修改用戶,由於它們會在mysql.user表的password列設置空串。到mysql5.6.7解決了這個問題。MariaDB可隨意使用。
語法:
CREATE [OR REPLACE] USER [IF NOT EXISTS] user_specification [,user_specification] ... [WITH resource_option [resource_option] ...] user_specification: username [authentication_option] authentication_option: IDENTIFIED BY 'authentication_string' resource_option: MAX_QUERIES_PER_HOUR count | MAX_UPDATE_PER_HOUR count | MAX_CONNECTIONS_PER_HOUR count | MAX_USER_CONNECTIONS count
例如:
create user 'longshuai'@'127.0.0.1' identified by '123456';
alter user和create user語法基本一致,但在MySQL中有讓密碼過時的功能,而在MariaDB中不支持該功能。
ALTER USER user_specification [, user_specification] ... user_specification: user PASSWORD EXPIRE
例如,讓剛纔建立的用戶過時。
MariaDB/MySQL中user的元數據信息都存放在mysql.user表中,可是在這個表中的信息分類不多,經常使用的就只有用戶類列和權限類列,沒有用戶的建立時間。
能夠經過新增一列來記錄用戶的建立時間。
alter table mysql.user add column create_time timestamp default current_timestamp;
這樣之後新建用戶都會記錄建立時間。可是顯然,對於已有的用戶是沒有記錄時間的,它們的值都爲'0000-00-00 00:00:00'。
MariaDB [mysql]> select host,user,create_time from mysql.user; +---------------------+-----------+---------------------+ | host | user | create_time | +---------------------+-----------+---------------------+ | localhost | root | 2018-04-21 05:58:19 | | 127.0.0.1 | root | 2018-04-21 05:58:19 | | ::1 | root | 2018-04-21 05:58:19 | | localhost | | 2018-04-21 05:58:19 | | 192.168.100.% | root | 2018-04-21 05:58:19 | | 192.168.100.1 | long | 2018-04-21 05:58:19 | | 127.0.0.1 | longshuai | 2018-04-21 05:58:19 | | 192.168.100.1 | longshuai | 0000-00-00 00:00:00 | +---------------------+-----------+---------------------+
可使用show grants語句查看某個user的權限信息。
例如:
MariaDB [mysql]> show grants for 'root'@'localhost'; Grants for root@localhost ----------------------------------------------------------------------------------------------------------------- GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' WITH GRANT OPTION GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION
MariaDB [mysql]>SHOW GRANTS FOR 'long'@'192.168.100.1';
Grants for long@192.168.100.1 ----------------------------------------------------------------------------------------------------------- GRANT USAGE ON *.* TO 'long'@'192.168.100.1' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' GRANT SELECT ON `test`.* TO 'long'@'192.168.100.1'
revoke命令回收權限時必須要明確指定回收的數據庫對象以及用戶名,其中usage權限沒法回收。特別要說明的是revoke all,當你覺得它會回收全部權限的時候,它可能一點權限都沒有回收。也就是說revoke命令的書寫很是嚴格。
用戶 'long'@'192.168.100.1' 在 *.* 上具備usage權限,在test.*上具備select權限。
MariaDB [mysql]> SHOW GRANTS FOR 'long'@'192.168.100.1'; Grants for long@192.168.100.1 ----------------------------------------------------------------------------------------------------------- GRANT USAGE ON *.* TO 'long'@'192.168.100.1' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' GRANT SELECT ON `test`.* TO 'long'@'192.168.100.1'
對該用戶在 *.* 上進行revoke all,再次查看權限,發現權限根本一點變化都沒有。由於usage權限沒法回收,而select權限是在test.*上而非*.*上。
REVOKE ALL ON *.* FROM 'long'@'192.168.100.1';
要回收test.*上的select權限,必須在revoke中指定test.*,而不能是 *.* 。如下兩個語句都能回收。
revoke select on test.* from 'long'@'192.168.100.1'; revoke all on test.* from 'long'@'192.168.100.1';
直接使用drop user命令或者從mysql.user表中刪除對應記錄。
drop user user_name1,username2...
注意,刪除表中用戶記錄的時候不會從現有用戶中回收對該表的權限,當下次再建立同名表的時候,會自動爲用戶授予該表的權限形成權限外流。
所以,建議使用drop user語句來刪除用戶。
(1)grant all on *.* to 'root'@'localhost' identified by '123456' with grant option; (2)grant usage on *.* to 'root'@'localhost' identified by '123456' with grant option;
使用usage權限表示在不影響現有權限的狀況下使用grant來修改密碼。
(3)set password [for 'root'@'localhost'] =password('123456');
password函數中必須加引號,不寫user時是爲當前用戶修改。
(4)alter user root@localhost identified by '123456'; (5)mysqladmin -uroot -h localhost -p'old_password' password 'new_password'; (6)update mysql.user set password=password('123456') where user='root' and host='localhost';
其中grant和set password語句能夠直接刷新權限表,其餘語句須要使用 flush privileges 或其餘刷新語句。
能夠在啓動mysql服務時使用mysqld_safe服務程序並指定"--skip-grant-tables"選項表示跳過受權表,這樣登錄mysql服務器將不須要任何權限,包括密碼認證也不須要,可是一樣受限的是不能操做任何權限相關的內容,好比修改權限,刷新受權表等。這一般是mysql管理員密碼忘記的時候使用的選項。因爲跳過受權表使得mysql服務器極不安全,任何用戶都能直接登陸服務器,因此一般和"--skip-networking"選項一塊兒使用來禁止來自網絡的服務器鏈接請求,這樣只能使用localhost或者127.0.0.1做爲host來登陸。
另外,使用mysqld_safe啓動無受權表的服務前要中止已有的MySQL實例。因爲跳過受權表沒法操做權限相關內容,因此修改mysql.user表中的管理員帳號的密碼字段是惟一修改方法。修改密碼後記得重啓MySQL服務。
步驟以下:
[root@xuexi mysql]# service mysqld stop [root@xuexi mysql]# mysqld_safe --skip-grant-tables --skip-networking & [root@xuexi mysql]# mysql mysql> update mysql.user set password=password("123456") where user='root' and host='localhost'; mysql> flush privileges; mysql> select user,host,password from mysql.user where user='root' and host='localhost'; +------+-----------+-------------------------------------------+ | user | host | password | +------+-----------+-------------------------------------------+ | root | localhost | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | +------+-----------+-------------------------------------------+ 1 row in set mysql> \q [root@xuexi mysql]# service mysqld stop [root@xuexi mysql]# service mysqld start [root@xuexi mysql]# mysql -uroot -p123456 mysql> \q
若是要找回多實例的密碼,則在mysqld_safe命令中使用 --defaults-file 指定對應的配置文件便可。