MYSQL权限系统实践操作,总结整理。匿名用户的问题直接搜索“匿名”
MySQL权限系统保证所有的用户只执行允许做的事情。当你连接MySQL服务器时,你的身份由
来决定。连接后发出请求后,系统根据你的身份和你想做什么来授予权限。
MySQL权限控制包含2个阶段:
服务器在存取控制的两个阶段使用mysql数据库中的user、db
表名 | user | db |
|---|---|---|
列范围 | Host | Host |
User | Db | |
Password | 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 | |
References_priv | References_priv | |
Reload_priv | ||
Shutdown_priv | ||
Process_priv | ||
File_priv | ||
Show_db_priv | ||
Super_priv | ||
Create_tmp_table_priv | Create_tmp_table_priv | |
Lock_tables_priv | Lock_tables_priv | |
Execute_priv | ||
Repl_slave_priv | ||
Repl_client_priv | ||
安全列 | ssl_type | |
ssl_cipher | ||
x509_issuer | ||
x509_subject | ||
资源控制列 | max_questions | |
max_updates | ||
max_connections | ||
max_user_connections |
对存取控制的第二阶段(请求证实),服务器执行请求验证以确保每个客户端有充分的权限满足各需求。除了user、db和host授权表,如果请求涉及表,服务器可以另外参考tables_priv和columns_priv表。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 |
为了对涉及保存程序的请求进行验证,服务器将查阅procs_priv表。该表具有以下列:
表名 | procs_priv |
|---|---|
范围列 | Host |
Db | |
User | |
Routine_name | |
Routine_type | |
权限列 | Proc_priv |
其它列 | Timestamp |
Grantor |
账户权限信息被存储在mysql数据库的user、db、host、tables_priv、columns_priv和procs_priv表中。在MySQL启动时并在**“权限更改何时生效”**所说的情况时,服务器将这些数据库表内容读入内存。
权限 | 列 | 上下文 |
|---|---|---|
CREATE | Create_priv | 数据库、表或索引 |
DROP | Drop_priv | 数据库或表 |
GRANT OPTION | Grant_priv | 数据库、表或保存的程序 |
REFERENCES | References_priv | 数据库或表 |
ALTER | Alter_priv | 表 |
DELETE | Delete_priv | 表 |
INDEX | Index_priv | 表 |
INSERT | Insert_priv | 表 |
SELECT | Select_priv | 表 |
UPDATE | Update_priv | 表 |
CREATE VIEW | Create_view_priv | 视图 |
SHOW VIEW | Show_view_priv | 视图 |
ALTER ROUTINE | Alter_routine_priv | 保存的程序 |
CREATE ROUTINE | Create_routine_priv | 保存的程序 |
EXECUTE | Execute_priv | 保存的程序 |
FILE | File_priv | 服务器主机上的文件访问 |
CREATE TEMPORARY TABLES | Create_tmp_table_priv | 服务器管理 |
LOCK TABLES | Lock_tables_priv | 服务器管理 |
CREATE USER | Create_user_priv | 服务器管理 |
PROCESS | Process_priv | 服务器管理 |
RELOAD | Reload_priv | 服务器管理 |
REPLICATION CLIENT | Repl_client_priv | 服务器管理 |
REPLICATION SLAVE | Repl_slave_priv | 服务器管理 |
SHOW DATABASES | Show_db_priv | 服务器管理 |
SHUTDOWN | Shutdown_priv | 服务器管理 |
SUPER | Super_priv | 服务器管理 |
当你想要访问MySQL服务器时,MySQL客户端程序一般要求你指定参数:
可以从命令行按照下述提示启动MySQL客户端(用shell>表示):
shell> MySQL -h host_name -u user_name -pyour_pass如果没有指定连接参数,MySQL客户端程序使用默认值:
这样, 对Unix用户joe,下列命令是等价的:
shell> MySQL -h localhost -u joe
shell> MySQL -h localhost
shell> MySQL -u joe
shell> MySQL其它MySQL客户端程序类似。
当你试图连接MySQL服务器时,服务器基于你的身份以及你是否能通过供应正确的密码验证身份来接受或拒绝连接。如果不是,服务器完全拒绝你的访问,否则,服务器接受连接,然后进入阶段2并且等待请求。
你的身份基于2个信息
身份检查使用user表(Host, User和Password)范围列执行。服务器只有在user表记录的Host和User列匹配客户端主机名和用户名并且提供了正确的密码时才接受连接。
在user表Host值的指定方法:
下面的例子显示出各种user表中Host和User值的组合如何应用于到来的连接:
Host值 | User值 | 被条目匹配的连接 |
|---|---|---|
‘thomas.loc.gov’ | ‘fred’ | fred, 从thomas.loc.gov 连接 |
‘thomas.loc.gov’ | ‘’ | 任何用户, 从thomas.loc.gov连接 |
‘%’ | ‘fred’ | fred, 从任何主机连接 |
‘%’ | ‘’ | 任何用户, 从任何主机连接 |
‘%.loc.gov’ | ‘fred’ | fred, 从在loc.gov域的任何主机连接 |
‘x.y.%’ | ‘fred’ | fred, 从x.y.net、x.y.com,x.y.edu等联接。(这或许无用) |
‘144.155.166.177’ | ‘fred’ | fred, 从有144.155.166.177 IP地址的主机连接 |
‘144.155.166.%’ | ‘fred’ | fred, 从144.155.166 C类子网的任何主机连接 |
当服务器读取表时,它首先以最具体的Host值排序。主机名和IP号是最具体的。’%'意味着“任何主机”并且是最不特定的。有相同Host值的条目首先以最具体的User值排序(空User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样:
+-----------+----------+-
| Host | User | …
+-----------+----------+-
| localhost | root | … ...
| localhost | | … ...
| % | jeffrey | … ...
| % | root | … ...
+-----------+----------+-当客户端试图连接时,服务器浏览排序的条目并使用找到的第一匹配。对于由jeffrey从localhost的连接,表内有两个条目匹配:Host和User值为’localhost’和’‘的条目,和值为’%'和’jeffrey’的条目。'localhost’条目首先匹配,服务器可以使用。
还有一个例子。假定user表看起来像这样:
+----------------+----------+-
| Host | User | …
+----------------+----------+-
| % | jeffrey | …
| thomas.loc.gov | | …
+----------------+----------+-排序后的表看起来像这样:
+----------------+----------+-
| Host | User | …
+----------------+----------+-
| thomas.loc.gov | | …
| % | jeffrey | …
+----------------+----------+-由jeffrey从thomas.loc.gov的连接与第一行匹配,而由jeffrey从whitehouse.gov的连接被第二个匹配。
普遍的误解是认为,对给定的用户名,当服务器试图对连接寻找匹配时,明确命名那个用户的所有条目将首先被使用。这明显不符合事实。先前的例子说明了这点,在那里由jeffrey从thomas.loc.gov的连接没被包含’jeffrey’作为User列值的行匹配,但是由没有用户名的题目匹配!结果是,jeffrey被鉴定为匿名用户,即使他连接时指定了用户名。
注意!host先匹配,有可能匹配上匿名用户!
如果你能够连接服务器,但你的权限不是你期望的,你可能被鉴定为其它账户。要想找出服务器用来鉴定你的账户,使用CURRENT_USER()函数。它返回user_name@host_name格式的值,说明User和Host 值匹配user表记录。假定jeffrey连接并发出下面的查询:
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost |
+----------------+这儿显示的结果说明user表行有空的User列值。换句话说,服务器将jeffrey视为匿名用户。
%并_可用于两个表的Host和Db列。它们与用LIKE操作符执行的模式匹配操作具有相同的含义。如果授权时你想使用某个字符,必须使用反斜现引用。例如,要想在数据库名中包括下划线(‘_’),在GRANT语句中用‘_’来指定。%Host值意味着“任何主机”,在db表中空Host值意味着“对进一步的信息咨询host表”(本节后面将描述的一个过程)。用布尔术语表示,前面关于用户权限如何计算的描述可以这样总结:
user表: global privileges
|
db表: database privileges
|
table_priv表: table privileges
|
column_priv表: column privileges一定要测试授权表中的行(例如,使用SHOW GRANTS或mysqlaccess),确保你的访问权限实际按你期望的方式被设置。
当mysqld启动时,所有授权表的内容被读进内存并且从此时生效。
当服务器注意到授权表被改变了时,现存的客户端连接有如下影响:
如果用GRANT、REVOKE或SET PASSWORD对授权表进行修改,服务器会注意到并立即重新将授权表载入内存。
如果你手动地修改授权表(使用INSERT、UPDATE或DELETE等等),你应该执行mysqladmin flush-privileges或mysqladmin reload告诉服务器再装载授权表,否则你的更改将不会生效,除非你重启服务器。
如果你直接更改了授权表但忘记重载,重启服务器后你的更改方生效。这样可能让你迷惑为什么你的更改没有什么变化!
当你试着联接MySQL服务器时,如果碰到问题,下面各项可以帮助你纠正问题:
确保服务器在运行。如果服务器没有运行,则你不能连接服务器。如果你视图连接服务器并看到下述消息,可能是服务器没有运行:
shell> mysql
RROR 2003: Can't connect to MySQL server on 'host_name' (111)
shell> mysql
ERROR 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111)也可能服务器正在运行,但你可能使用与服务器上侦听的不一样的TCP/IP端口、命名管道或Unix套接字文件。你可以调用客户端程序,指定端口选项来指示正确的端口或套接字选项来指示正确的命名管道或Unix套接字文件。要找出套接字文件的地点,应:
shell> netstat -ln | grep mysql可以用两种方式创建MySQL账户:
下面的语句使用GRANT来设置四个新账户:
GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost' IDENTIFIED BY 'some_pass'
WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%' IDENTIFIED BY 'some_pass'
WITH GRANT OPTION;
GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';
GRANT USAGE ON *.* TO 'dummy'@'localhost';下面的例子创建3个账户,允许它们访问专用数据库。每个账户的用户名为custom,密码为obscure。
-- 第1个账户可以访问bankaccount数据库,但只能从本机访问。
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON bankaccount.*
TO 'custom'@'localhost'
IDENTIFIED BY 'obscure';
-- 第2个账户可以访问expenses数据库,但只能从主机whitehouse.gov访问。
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON expenses.*
TO 'custom'@'whitehouse.gov'
IDENTIFIED BY 'obscure';
-- 第3个账户可以访问customer数据库,但只能从主机server.domain访问。
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON customer.*
TO 'custom'@'server.domain'
IDENTIFIED BY 'obscure';测试验证
-- t1能看到testdb的所有表,能查询不能写入
grant select on testdb.* to 't1'@'%' identified by '333';
-- t1只能看到testtbl1,能查询不能写入
grant select on testdb.testtbl1 to 't2'@'%' identified by '333';
-- t1 t2的user表中全是N
-- t1在DB表中记录权限,t2没有数据
mysql> select * from db where user = 't1'\G
*************************** 1. row ***************************
Host: %
Db: testdb
User: t1
Select_priv: Y
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Execute_priv: N
Event_priv: N
Trigger_priv: N
-- t2在tables_priv表中记录权限,t1没有数据
mysql> select * from tables_priv where user='t2'\G
*************************** 1. row ***************************
Host: %
Db: testdb
User: t2
Table_name: testtbl1
Grantor: aliyun_root@127.0.0.1
Timestamp: 0000-00-00 00:00:00
Table_priv: Select
Column_priv:方式一:限制MySQL服务器资源使用的一个方法是将max_user_connections系统变量设置为非零值。但是,该方法严格限于全局,不允许管理具体账户。并且,它只限制使用单一账户同时连接的数量,而不是客户端连接后的操作。
方式二:
做为使用该特性的先决条件,mysql数据库的user表必须包含资源相关的列。资源限制保存在max_questions、max_updates、max_connections和max_user_connections列内
要想用GRANT语句设置资源限制,使WITH子句来命名每个要限制的资源和根据每小时记数的限制值。例如,要想只以限制方式创建可以访问customer数据库的新账户,执行该语句:
GRANT ALL ON customer.* TO 't3'@'localhost'
IDENTIFIED BY '333'
WITH MAX_QUERIES_PER_HOUR 20
MAX_UPDATES_PER_HOUR 10
MAX_CONNECTIONS_PER_HOUR 5
MAX_USER_CONNECTIONS 2;
select max_questions,max_updates,max_connections,max_user_connections from user where user='t3';
+---------------+-------------+-----------------+----------------------+
| max_questions | max_updates | max_connections | max_user_connections |
+---------------+-------------+-----------------+----------------------+
| 20 | 10 | 5 | 2 |
+---------------+-------------+-----------------+----------------------+要想设置或更改已有账户的限制,在全局级别使用GRANT USAGE语句(在*.*)。下面的语句可以将francis的查询限制更改为100:
GRANT USAGE ON *.* TO 'francis'@'localhost' WITH MAX_QUERIES_PER_HOUR 100;该语句没有改变账户的已有权限,只修改了指定的限制值。
要想取消已有限制,将该值设置为零。例如,要想取消francis每小时可以连接的次数的限制,使用该语句:
GRANT USAGE ON *.* TO 'francis'@'localhost' WITH MAX_CONNECTIONS_PER_HOUR 0;测试MAX_USER_CONNECTIONS
mysql> grant usage on *.* to 't3'@'localhost' with MAX_USER_CONNECTIONS 1;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
#mysql -ut3 -S /mysqldata/tmp3148/mysql.sock -p333
mysql>
#mysql -S /home/mysql/data3148/tmp/mysql.sock -ut3 -p333
ERROR 1226 (42000): User 't3' has exceeded the 'max_user_connections' resource (current value: 1)有权限修改mysql库的用户才能修改别人的密码
SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');
GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit';mysql> SET PASSWORD FOR 't3'@'%' = PASSWORD('123');
ERROR 1044 (42000): Access denied for user 't3'@'localhost' to database 'mysql'
-- 修改自己的密码可省略
mysql> SET PASSWORD = PASSWORD('123');
Query OK, 0 rows affected, 1 warning (0.01 sec)在管理级别,你决不能将mysql.user表的访问权限授予任何非管理账户。
-- root登陆
create table tbl1(a int, b int, c int, d int);
insert into tbl1 values (1,2,3,4);
select * from tbl1;
+------+------+------+------+
| a | b | c | d |
+------+------+------+------+
| 1 | 2 | 3 | 4 |
+------+------+------+------+
grant select(a) on testdb.tbl1 to t4 identified by '333';
grant insert(a) on testdb.tbl1 to t6 identified by '333';
-- t4登陆:只能查询a列
mysql -ut4 -S /mysqldata/tmp3148/mysql.sock -p333
mysql> select * from tbl1;
ERROR 1142 (42000): SELECT command denied to user 't4'@'localhost' for table 'tbl1'
mysql> select a from tbl1;
+------+
| a |
+------+
| 1 |
+------+
mysql> show grants;
+-------------------------------------------------+
| Grants for t4@% |
+-------------------------------------------------+
| GRANT USAGE ON *.* TO 't4'@'%' |
| GRANT SELECT (a) ON `testdb`.`tbl1` TO 't4'@'%' |
+-------------------------------------------------+
-- t6登陆:只能插入a列
mysql -ut6 -S /mysqldata/tmp3148/mysql.sock -p333
mysql> insert into tbl1 (a) values (1);
Query OK, 1 row affected (0.01 sec)
mysql> insert into tbl1 (b) values (1);
ERROR 1143 (42000): INSERT command denied to user 't6'@'localhost' for column 'b' in table 'tbl1'
mysql> show grants;
+-------------------------------------------------+
| Grants for t6@% |
+-------------------------------------------------+
| GRANT USAGE ON *.* TO 't6'@'%' |
| GRANT INSERT (a) ON `testdb`.`tbl1` TO 't6'@'%' |
+-------------------------------------------------+手册5.8.7需要再整理
GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ...
ON [object_type] {tbl_name | * | *.* | db_name.*}
TO user
[IDENTIFIED BY [PASSWORD] 'password']
[, user [IDENTIFIED BY [PASSWORD] 'password']] ...
[REQUIRE
NONE |
[{SSL| X509}]
[CIPHER 'cipher' [AND]]
[ISSUER 'issuer' [AND]]
[SUBJECT 'subject']]
[WITH with_option [with_option] ...]
object_type =
TABLE
| FUNCTION
| PROCEDURE
with_option =
GRANT OPTION
| MAX_QUERIES_PER_HOUR count
| MAX_UPDATES_PER_HOUR count
| MAX_CONNECTIONS_PER_HOUR count
| MAX_USER_CONNECTIONS count
REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ...
ON [object_type] {tbl_name | * | *.* | db_name.*}
FROM user [, user] ...
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...授予的权限可以分为多个层级
GRANT ALL ON *.*和REVOKE ALL ON *.*只授予和撤销全局权限。
GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤销数据库权限。
GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤销表权限。
mysql.columns_priv表中。当使用REVOKE时,您必须指定与被授权列相同的列。
CREATE ROUTINE, ALTER ROUTINE, EXECUTE和GRANT权限适用于已存储的子程序。这些权限可以被授予为全局层级和数据库层级。而且,除了CREATE ROUTINE外,这些权限可以被授予为子程序层级,并存储在mysql.procs_priv表中。
权限表
权限 | 意义 |
|---|---|
ALL [PRIVILEGES] | 设置除GRANT OPTION之外的所有简单权限 |
ALTER | 允许使用ALTER TABLE |
ALTER ROUTINE | 更改或取消已存储的子程序 |
CREATE | 允许使用CREATE TABLE |
CREATE ROUTINE | 创建已存储的子程序 |
CREATE TEMPORARY TABLES | 允许使用CREATE TEMPORARY TABLE |
CREATE USER | 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。 |
CREATE VIEW | 允许使用CREATE VIEW |
DELETE | 允许使用DELETE |
DROP | 允许使用DROP TABLE |
EXECUTE | 允许用户运行已存储的子程序 |
FILE | 允许使用SELECT…INTO OUTFILE和LOAD DATA INFILE |
INDEX | 允许使用CREATE INDEX和DROP INDEX |
INSERT | 允许使用INSERT |
LOCK TABLES | 允许对您拥有SELECT权限的表使用LOCK TABLES |
PROCESS | 允许使用SHOW FULL PROCESSLIST |
REFERENCES | 未被实施 |
RELOAD | 允许使用FLUSH |
REPLICATION CLIENT | 允许用户询问从属服务器或主服务器的地址 |
REPLICATION SLAVE | 用于复制型从属服务器(从主服务器中读取二进制日志事件) |
SELECT | 允许使用SELECT |
SHOW DATABASES | SHOW DATABASES显示所有数据库 |
SHOW VIEW | 允许使用SHOW CREATE VIEW |
SHUTDOWN | 允许使用mysqladmin shutdown |
SUPER | 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。 |
UPDATE | 允许使用UPDATE |
USAGE | “无权限”的同义词 |
GRANT OPTION | 允许授予权限 |
使用SHOW GRANTS来确定帐户拥有什么权限
FILEPROCESS
RELOAD
REPLICATION CLIENT
REPLICATION SLAVE
SHOW DATABASES
SHUTDOWN
SUPER权限是管理性权限,只能进行全局授权(使用ON *.*语法)。