MySQL的一些小tip

  • 2019 年 11 月 6 日
  • 筆記

MySQL的一些小tip

1

Create user和grant 的几点说明

我们都知道Create user和grant for都可以用来创建一个用户,那么这两个语句的处理上有什么区别呢?这里我们从MySQL 5.5和MySQL 5.7两个版本来看。

首先使用MySQL 5.5版本,我们假定需要创建一个用户yeyz,它的host是本地localhost,分别使用这两种创建语句来创建这个用户,首先是grant语句,grant语句一般直接跟一些给定的权限:

[email protected]:(none) ::>>select version();  +------------+  | version()  |  +------------+  | 5.5.19-log |  +------------+   row in set (0.00 sec)  [email protected]:(none) ::>>drop user yeyz@localhost;  Query OK,  rows affected (0.00 sec)    [email protected]:(none) ::>>grant select,create on *.* to yeyz@localhost identified by '123456';  Query OK,  rows affected (0.00 sec)    [email protected]:(none) ::>>show grants for yeyz@localhost;  +----------------------------------------------------------------------------------------------------------------------+  | Grants for yeyz@localhost                                                                                            |  +----------------------------------------------------------------------------------------------------------------------+  | GRANT SELECT, CREATE ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |  +----------------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)  

上面我们给定了create和select权限,我们使用新的用户登录,可以发现:

mysql--yeyz@localhost:(none) ::>>create database yeyz;  Query OK,  row affected (0.00 sec)    mysql--yeyz@localhost:(none) ::>>show databases;  +--------------------+  | Database           |  +--------------------+  | information_schema |  | mysql              |  | performance_schema |  | yeyz               |  +--------------------+   rows in set (0.01 sec)  

这个用户可以创建一个新的数据库。

我们删掉前面的yeyz用户,再来看看create语句:

[email protected]:(none) ::>>select version();  +------------+  | version()  |  +------------+  | 5.5.19-log |  +------------+   row in set (0.00 sec)      [email protected]:(none) ::>>create user yeyz@localhost identified by '123456';  Query OK,  rows affected (0.00 sec)  

然后我们查询这个用户的相关权限:

show grants for yeyz@localhost;  +-------------------------------------------------------------------------------------------------------------+  | Grants for yeyz@localhost                                                                                   |  +-------------------------------------------------------------------------------------------------------------+  | GRANT USAGE ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |  +-------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)  

可以看到,已经给出了usage权限,这里解释一下,这个usage权限只能连接数据库,什么也不能做,我们验证一下,用这个用户连接数据库,结果如下:

[dba_mysql@tk-dba-mysql-stat-10-104 ~]$ /usr/local/mysql/bin/mysql -uyeyz --socket=/data/mysql_4306/tmp/mysql.sock --port= -p -hlocalhost  Enter password:  Welcome to the MySQL monitor.  Commands end with ; or g.  Your MySQL connection id is  Server version: 5.5.19-log MySQL Community Server (GPL)    Copyright (c) , , Oracle and/or its affiliates. All rights reserved.    Oracle is a registered trademark of Oracle Corporation and/or its  affiliates. Other names may be trademarks of their respective  owners.    Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.    mysql--yeyz@localhost:(none) ::>>show databases;  +--------------------+  | Database           |  +--------------------+  | information_schema |  +--------------------+   row in set (0.01 sec)    mysql--yeyz@localhost:(none) ::>>create database yeyz;  ERROR  (): Access denied for user 'yeyz'@'localhost' to database 'yeyz'  mysql--yeyz@localhost:(none) ::>>  

我们可以看到这个用户只能连接数据库,查看数据库里面的表,连最基本的创建数据库的权限都没有。如果想要create user这种方式也可以用户创建数据库的权限,需要额外使用grant的方式分配相关权限,如下:

[email protected]:(none) ::>>show grants for yeyz@localhost;  +-------------------------------------------------------------------------------------------------------------+  | Grants for yeyz@localhost                                                                                   |  +-------------------------------------------------------------------------------------------------------------+  | GRANT USAGE ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |  +-------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)    [email protected]:(none) ::>>grant select,create on *.* to yeyz@localhost;  Query OK,  rows affected (0.00 sec)    [email protected]:(none) ::>>show grants for yeyz@localhost;  +----------------------------------------------------------------------------------------------------------------------+  | Grants for yeyz@localhost                                                                                            |  +----------------------------------------------------------------------------------------------------------------------+  | GRANT SELECT, CREATE ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |  +----------------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)    [email protected]:(none) ::>>create database yeyz;  Query OK,  row affected (0.00 sec)  

在上面的基础上,我们使用grant语句重新给定select和create权限,发现已经可以创建数据库了。

结论:

1.create user方法创建用户相当于执行了grant usage,它创建的用户没有任何的权限,只能登陆到服务上,没有任何权限。若想分配相关权限,需要使用grant语句重新分配。

2.grant语法创建的用户可以直接赋予相应权限,用户创建成功之后即可使用相关权限。

大家可能发现了,前面说了两个版本,MySQL5.5和MySQL5.7,上面的结论实在MySQL5.5的基础上得到的,那么5.7又是怎么回事呢?这里解释一下,MySQL 5.7版本中create user和grant的区别跟上面的相同,但是有一个细节需要注意:

mysql> create user test@localhost identified by '123456';  Query OK,  rows affected (0.03 sec)    mysql> show grants for test@localhost;  +------------------------------------------+  | Grants for test@localhost                |  +------------------------------------------+  | GRANT USAGE ON *.* TO 'test'@'localhost' |  +------------------------------------------+   row in set (0.00 sec)    mysql> show create user test@localhost;  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+  | CREATE USER for test@localhost                                                                                                                                            |  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+  | CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK |  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)    mysql> select version();  +------------+  | version()  |  +------------+  | 5.7.22-log |  +------------+   row in set (0.00 sec)  

从上面的测试我们可以看出,在MySQL5.7版本中,当我们创建用户使用create user的方法时,使用show grant for语句是没法看到用户的密码的,而使用show create user方法便可以看到用户的密码。而在MySQL5.5版本中,我们使用show create user的方式时会直接报错。

[email protected]:(none) ::>>show create user yeyz@localhost;  ERROR  (): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'user yeyz@localhost' at line  [email protected]:(none) ::>>show grants for yeyz@localhost;  +----------------------------------------------------------------------------------------------------------------------+  | Grants for yeyz@localhost                                                                                            |  +----------------------------------------------------------------------------------------------------------------------+  | GRANT SELECT, CREATE ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |  +----------------------------------------------------------------------------------------------------------------------+   row in set (0.00 sec)    [email protected]:(none) ::>>select version();  +------------+  | version()  |  +------------+  | 5.5.19-log |  +------------+   row in set (0.00 sec)  

这里又有一个问题,既然show create user方法创建的用户无法使用show grants for看到密码,那么grant 语法创建的用户呢?是不是也看不到?来看实验:

mysql> grant select on *.* to test1@localhost identified by '123456';  Query OK,  rows affected,  warning (0.02 sec)    mysql> show grants for test1@localhost;  +--------------------------------------------+  | Grants for test1@localhost                 |  +--------------------------------------------+  | GRANT SELECT ON *.* TO 'test1'@'localhost' |  +--------------------------------------------+   row in set (0.00 sec)  

这样,这个问题一目了然,显然也无法看到。

简单总结:

  1. MySQL5.5不支持show create user语句,只支持show grants for语句;
  2. MySQL5.7中支持show create user语句和show grants for语句,但是show grants for语句无法查看所创建的用户的密码;

2

MySQL5.5和MySQL5.7的user表区别

上面讲到了MySQL5.5和MySQL5.7的创建用户的区别,这里我们说说MySQL5.5和MySQL5.7里面的user表的区别。

这个问题是由线上的一个工单引出的,前两天在处理一个工单的时候,需要查询查询账户创建时候的密码,于是直接使用下面的语句进行查询:

[email protected]:(none) ::>>select user,host,password from mysql.user;  ERROR  (S22): Unknown column 'password' in 'field list'  

发现这个user表里面居然没有password这个选项,然后desc查询了一下mysql.user表里面的字段:

[email protected]:(none) ::>>desc mysql.user;  +------------------------+-----------------------------------+------+-----+-----------------------+-------+  | Field                  | Type                              | Null | Key | Default               | Extra |  +------------------------+-----------------------------------+------+-----+-----------------------+-------+  | Host                   | char()                          | NO   | PRI |                       |       |  | User                   | char()                          | NO   | PRI |                       |       |  | Select_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Insert_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Update_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Delete_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Create_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Drop_priv              | enum('N','Y')                     | NO   |     | N                     |       |  | Reload_priv            | enum('N','Y')                     | NO   |     | N                     |       |  | Shutdown_priv          | enum('N','Y')                     | NO   |     | N                     |       |  | Process_priv           | enum('N','Y')                     | NO   |     | N                     |       |  | File_priv              | enum('N','Y')                     | NO   |     | N                     |       |  | Grant_priv             | enum('N','Y')                     | NO   |     | N                     |       |  | References_priv        | enum('N','Y')                     | NO   |     | N                     |       |  | Index_priv             | enum('N','Y')                     | NO   |     | N                     |       |  | Alter_priv             | enum('N','Y')                     | NO   |     | N                     |       |  | Show_db_priv           | enum('N','Y')                     | NO   |     | N                     |       |  | Super_priv             | enum('N','Y')                     | NO   |     | N                     |       |  | Create_tmp_table_priv  | enum('N','Y')                     | NO   |     | N                     |       |  | Lock_tables_priv       | enum('N','Y')                     | NO   |     | N                     |       |  | Execute_priv           | enum('N','Y')                     | NO   |     | N                     |       |  | Repl_slave_priv        | enum('N','Y')                     | NO   |     | N                     |       |  | Repl_client_priv       | enum('N','Y')                     | NO   |     | N                     |       |  | Create_view_priv       | enum('N','Y')                     | NO   |     | N                     |       |  | Show_view_priv         | enum('N','Y')                     | NO   |     | N                     |       |  | Create_routine_priv    | enum('N','Y')                     | NO   |     | N                     |       |  | Alter_routine_priv     | enum('N','Y')                     | NO   |     | N                     |       |  | Create_user_priv       | enum('N','Y')                     | NO   |     | N                     |       |  | Event_priv             | enum('N','Y')                     | NO   |     | N                     |       |  | Trigger_priv           | enum('N','Y')                     | NO   |     | N                     |       |  | Create_tablespace_priv | enum('N','Y')                     | NO   |     | N                     |       |  | ssl_type               | enum('','ANY','X509','SPECIFIED') | NO   |     |                       |       |  | ssl_cipher             | blob                              | NO   |     | NULL                  |       |  | x509_issuer            | blob                              | NO   |     | NULL                  |       |  | x509_subject           | blob                              | NO   |     | NULL                  |       |  | max_questions          | int() unsigned                  | NO   |     |                      |       |  | max_updates            | int() unsigned                  | NO   |     |                      |       |  | max_connections        | int() unsigned                  | NO   |     |                      |       |  | max_user_connections   | int() unsigned                  | NO   |     |                      |       |  | plugin                 | char()                          | NO   |     | mysql_native_password |       |  | authentication_string  | text                              | YES  |     | NULL                  |       |  | password_expired       | enum('N','Y')                     | NO   |     | N                     |       |  | password_last_changed  | timestamp                         | YES  |     | NULL                  |       |  | password_lifetime      | smallint() unsigned              | YES  |     | NULL                  |       |  | account_locked         | enum('N','Y')                     | NO   |     | N                     |       |  +------------------------+-----------------------------------+------+-----+-----------------------+-------+   rows in set (0.00 sec)  

发现password字段在MySQL5.7版本中已经被拿掉了,取而代之的是authentication_string,查看authentication_string可以发现:

[email protected]:(none) ::>>select user,host,authentication_string from mysql.user;  +---------------------+---------------+-------------------------------------------+  | user                | host          | authentication_string                     |  +---------------------+---------------+-------------------------------------------+  | root                | localhost     | *B66B5AD56Exxxxxxxxxxxx9AF81952D7F403 |  | mysql.sys           | localhost     | *THISISNOTAVALIxxxxxxxxxxxATCANBEUSEDHERE |  | dba_admin           | 127.0.0.1     | *ExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxE |  +---------------------+---------------+-------------------------------------------+   rows in set (0.00 sec)  

而在MySQL 5.5的版本中,我们可以看到password的字段是存在的:

[email protected]:(none) ::>>select user,host,password,authentication_string from mysql.user;  +------------------+-----------------+-------------------------------------------+-----------------------+  | user             | host            | password                                  | authentication_string |  +------------------+-----------------+-------------------------------------------+-----------------------+  | root             | localhost       | *xxxxxxxxxxx881A495C5B7C199DCB2DE15A740FA |                       |  | dba_yeyz         | localhost       | *xxxxxxxxxxxxx9105EE4568DDA7DC67ED2CA2AD9 | NULL                  |  | yeyz             | localhost       | *xxxxxxxxxxxx29105EE4568DDA7DC67ED2CA2AD9 | NULL                  |  +------------------+-----------------+-------------------------------------------+-----------------------+   rows in set (0.00 sec)  

结论:

MySQL5.5中存在password字段和authentication_string字段,但是后者的值为空值。

MySQL5.7版本中的已经不存在password字段,取而代之的是authentication_string字段,该字段存储加密的密码值;