Mysql 创建、删除用户、权限管理以及flush privileges的使用(很多人只是会使用sql语句,但是对用户以及用户权限的概念比较模糊)

1,927 阅读5分钟

Time:2019-8-15 21.42 Site:深圳科兴科学院 Author: strivewang

摘要

  1. 第一部分是介绍Mysql创建用户以及相应的权限介绍。
  2. 第二部分细节介绍了Mysql不同维度的权限控制
  3. 第三部分讲解了权限控制

1. Mysql创建用户

第一条语句的逻辑是创建一个用户’user'@'%’,密码是 password。用户名是user, host是%,表示所有的ip
create user 'ua'@'%' identified by 'password';   

第二条语句的逻辑是创建一个用户’user'@'192.168.0.1’,密码是 password。用户名是user, host是192.168.0.1,表示所有的ip
create user 'ua'@'192.168.0.1' identified by 'password';   

这条命令做了两个动作:

  1. 磁盘上,往 mysql.user 表里插入一行,由于没有指定权限,所以这行数据上表示所有的权限字段都是 N。
  2. 内存上,往数组 acl_users 里插入一个 acl_user 对象,这个对象的access 字段值为 0 。 图一就是用户 ua 的状态图
    图一 权限详细图

2. 全局权限

2.1 授予全局权限

全局权限:作用于整个 MySQL 实例,这些权限信息保存在 Mysql 库的 user 表中,如果需要给一个用户赋予最高权限,就是:

grant all privileges on *.* to 'user'@'%' with grant option;

这个 grant 命令做了两个动作:

  1. 磁盘上,将 mysql.user 表里,用户’user@’%' 这一行所有表示权限的字段修改为 ‘Y'
  2. 内存中,从数组acl_users 中找到这个用户的对象,将acess值(权限位)修改为二进制的 "全1".

2.2 取消用户全局权限:

revoke all privileges on *.* from 'user'@'%';

这个 grant 命令做了两个动作:

  1. 磁盘上,将 mysql.user 表里,用户’user@’%' 这一行所有表示权限的字段修改为 ‘N'
  2. 内存中,从数组acl_users 中找到这个用户的对象,将acess值(权限位)修改为二进制的 "全0".

3. DB权限

除了全局权限,Mysql也支持库、表、列等权限的定义。

3.1 授予用户指定库权限

#授予ua用户db1库所有的权限
grant all privileges on db1.* to 'ua'@'%' with grant option;

基于库的权限记录保存在 mysql.db 中,在内存里则保存在数组acl_dbs中,这个grant命令做了如下两个操作:

  1. 磁盘上,往mysql.db 表中插入一行记录,所有权限字段设置为 “Y”。
  2. 内存里, 增加一个对象到数组acl_dbs 中,这个对象的权限位设为 “全1”。

下图就是当前用户 ua 在 DB表中的的权限状态:

图2 ua用户的数据库权限表
数据库每次需要判断一个用户对一个数据库读写权限的时候,都需要遍历一次 acl_dbs 数组,根据User、host 和 db 找到匹配的对象,然后根据对象的权限位进行判断。

grant 修改 db 权限的时候,对磁盘和内存是同时生效的。

4. 表权限、列权限

除了全局权限、DB级别的权限之外,Mysql还支持更细粒度的表权限和列权限。其中表权限定义在mysql.table_priv,列权限定义在mysql.columns_priv中。这两种权限,组合起来存放在内存的Hash结构column_priv_hash中。

这两种权限的命令如下:


create table db1.t1(id int, a int);

# 赋予用户ua 库db1的t1表权限
grant all privileges on db1.t1 to 'ua'@'%' with grant option;

# 赋予用户ua 读id、插入id,a列的权限
GRANT SELECT(id), INSERT (id,a) ON mydb.mytbl TO 'ua'@'%' with grant option;

和 db 权限类似,表、列的权限每次 grant 的时候都会修改数据表,也会同步修改内存中的 hash 结构。因此这两个操作会马上影响已存在的链接。

5. flush privileges 问题

==既然 grant 每次执行完就是即时生效, 那为什么有时候需要执行 flush privileges 呢?==

  1. flush privileges 命令会清空 acl_users 数组,然后从 mysql.user 中重新读取数据加载到内存当中,重新构造一个 acl_users 数组。换句话说就是以数据表中的数据为准,将内存中的权限数组重新加载一边。

  2. 其实每次 grant 之后是不需要执行 flush privileges 的,只有当内存中的数据权限和磁盘表中的数据不同的时候,才需要执行 flush privileges 。如果我们规范的使用 grant、revoke,就不需要执行 flush privileges 。

因此,正常情况下,执行完 grant 之后,就不需要执行 flush privileges 。

5.1 flush privileges 使用场景

从上面分析得出,使用 flush privileges 的场景,无非就是 内存中权限数据跟磁盘数据表权限数据不一致,需要使用 flush privileges 来同步内存中的权限数据。

这种数据不一致,往往都是不规则的命令造成的,比如直接操作 mysql.user 表等等。 通过下面的表来解释一下不规范的操作导致的需要使用 flush privileges 来使权限数据一致。

图3
client A 在T3 时刻已经通过操作 mysql.user表,删除了 user=ua的用户,但是 client B 在T4依然可以使用这个账户链接数据库,client B 在T4能成功链接数据库的原因就是内存中的 acl_users 中还有这个用户,所以client B 在T4可以成功连接。在T5 使用了 flush privileges 命令之后,Client B 再链接,就会报错。

所以,直接操作数据库系统表是不规范的操作,就会导致内存中的权限数据和磁盘中的数据不一致。

还有更奇怪的现象如下图4:

图4
在T3时刻,通过直接操作 mysql.user表,直接删除了数据表中的记录,而内存中的数据还在,这就导致了下面这两个问题: T4时刻,赋予用户权限失败,这是因为数据表中已经没有了这个用户。 T5时刻,再次创建该用户失败,这是因为内存中依然存在该用户。

总结一下Mysql 中权限的作用以及在内存中和磁盘中存在的位置,如图5:

图5

本人的学习公众号,欢迎大家骚扰讨论

在这里插入图片描述
本人csdn博客链接: blog.csdn.net/weiaiyishen…