这一部分我们将会讨论如何为我们的MySQL服务器客户端设置帐户。我们将会讨论下面的一些问题:
1在MySQL中使用的帐户的用户以及密码的含义并与我们在操作系统中使用的用户以及密码进行比较
2如何设置新的帐户以及删除已经存在的帐户
3如何更改密码
4安全使用密码向导
5如何使用SSL进行安全连接
MySQL用户名与密码
MySQL的用户帐户是从用户名以及用户可以使用来与服务器进行连接的客户端主机或是主机的角度来进行定义的。用户帐户也会有一个密码。MySQL中使用用户名与密码的方式与操作系统使用用户名与密码的方式之间存在着下面的一些不同:
1 MySQL为授权目的而使用的用户名与我们在Windows或是Unix操作系统中使用的用户名并没有什么的关系。在Unix系统上,大多数的MySQL 客户端都会试着使用当前的用户名作为MySQL的用户名进行登陆,但是那仅仅是为了方便。默认的情况可以很容易被覆盖,因为客户端程序允许任何的用户使用 -u或是--user选项。因为这就意味着任何人都可以使用任何的用户试图与服务器进行连接,我们并不需要以任何方式创建一个安全数据库,除非第一个 MySQL的用户都有密码。任何一个为一个用户指定了一个用户名而没有密码的人都有可以成功的与数据库服务器建立连接。
2 MySQL的用户名可以长达16个字符长。这个限制在MySQL服务器与客户端中是硬编码的,而试着修改MySQL数据库中表的定义来进行改变的方法并不会起作用。
注意:我们不要试着用任何的方法来修改mysql数据库的表,除非我们是使用MySQL发行版本中为了这一目的而提供的脚本。试着重新定义MySQL系统表的行为会导致不可预知的结果。
操作系统的用户名与与MySQL的用户名并没有直接的关系,甚至他们的最大长度也是不同的。例如:Unix的用户名最长为8个字符。
3 MySQL的密码与我们登陆操作系统使用的密码也没有关系。在我们登陆Windows或是Unix时使用的密码与我们访问MySQL数据库服务器所使用的密码之间并没有直接的联系。
4 MySQL使用他自己的算法对密码进行加密。这个加密与Unix的登陆过程的加密是不同的。MySQL的密码加密是与由PASSWORD()SQL函数实现的相同。Unix密码的加密与由ENCRYPT()SQL函数实现的相同。
当我们使用命令行客户端与MySQL服务器建立连接时,我们要为我们将要使用的幅度指定用户名与密码:
shell> mysql --user=monty --password=guess db_name
如果我们喜欢简写的形式,我们的命令如下:
shell> mysql -u monty -pguess db_name
在-p选项与接下来的密码之间并没有空格。
在上面的命令中包含密码,这是一个安全安全隐患。要避免这样,我们可以指定--password或是-p而不指定任何接下来的内容:
shell> mysql --user=monty --password db_name
shell> mysql -u monty -p db_name
客户端程序会打印出一个提示并等待我们输入密码。
在某一些系统上,MySQL为密码提示所使用的库调用会自动设置成为8个字答的限制。这是系统库的问题而不是MySQL的问题。事实上,MySQL并没有密码长度的限制。为了解决这个问题,将我们的MySQL密码改为8个或是更少一些的字符长度,或者是将我们的密码放在一个可选的文件中。
添加新的MySQL帐户
我们可以用两种方法创建MySQL帐户:
1 通过使用GRANT语句
2 直接操作MySQL的数据表
其中较好的办法就是使用GRANT语句,因为他们更为简洁而又更少的错误。
创建帐户另外的选择就是使用一些可用的第三方程序,如phpMyAdmin.
下面的例子显示了如何使用mysql客户端程序设置新的用户。
首先,使用mysql程序以root身份与MySQL服务器建立连接:
shell> mysql --user=root mysql
如果我们为我们的root帐户设置了密码,我们就要使用--password或是-p选项。
以root身分与服务器建立连接以后,我们就可以添加新的帐户了。下面的语句使用GRANT来设置新的帐户:
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'
-> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%'
-> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';
mysql> GRANT USAGE ON *.* TO 'dummy'@'localhost';
由GRANT语句创建的用户有下面的一些属性:
1 这两个帐户以monty为用户名,以some_pass为密码。这个帐户都是超级帐户,拥有全部的权限可以做任何的事情。其中一个(’monty’@’localhost’)只可以用来从本地机器进行连接访问,另一个可以从任何的主机进行连接访问。在这里我们要注意的是将monty 帐户设置成为以monty身份可以从任何地方进行连接是必要的。如如没有本地帐户,当monty从本地主机进行连接时就会优先使用 mysql_install_db为本地主机所创建的匿名帐户。所以,monty就会当作匿名帐户处理。这是因为匿名帐户比起’monty’@'%'来有一个更为特殊的Host列,所以在user表中的排序更为靠前。
2 一个帐户以admin为用户但是却没有密码。这个帐户可以在从本地主机连接时使用。这个帐户有RELOAD和PROCESS管理权限。这些权限可以允许 admin用户执行mysqladmin reload,mysqladmin refresh,mysqladmin flush-xxx,mysqladmin processlist等命令。但是却没有访问数据库的权限。我们可以在以后通过执行GRANT语句来添加这些权限。
3 一个帐户以dummy为用户但是却没有密码。这个帐户只可以从本地主机进行连接。但是这个帐户却没有任何的权限。GRANT语句中的USAGE权限可以允许我们创建一个帐户但是却不给他以任何的权限。这样的作用与将全部的全局权限设为N相同。这样MySQL就会认为我们会在以后为这个帐户指定特殊的权限。
与GRANT相对的,我们可以通过执行插入语句并且告诉服务器使用FLUSH PRIVILEGES重新装入授予表来直接的创建同样的帐户:
shell> mysql --user=root mysql
mysql> INSERT INTO user
-> VALUES('localhost','monty',PASSWORD('some_pass'),
-> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user
-> VALUES('%','monty',PASSWORD('some_pass'),
-> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user SET Host='localhost',User='admin',
-> Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;
当我们使用INSERT语句来创建帐户时使用FLUSH PRIVILEGES的原因是告诉服务器重新读取授权表。否则,真到我们重新启动服务器我们的更改才会生效。如果使用GRANT,那么FLUSH PRIVILEGES不是必须的。
在INSERT语句中使用PASSWORD函数的原因是要加密密码。GRANT语句已经为我们的密码进行加密,所以这时PASSWORD并不是必須的。
Y值为帐户设置了权限。对于admin帐户,也许我们需要使用SET来得到更多的可读的扩展INSERT语法。
对于dummy帐户的INSERT语句,只有user表记录中的Host,User,Password列进行了赋值。权限列中并没有进行明显示的赋值,所以MySQL将他们全部设置成为默认的N。这与GRANT USAGE的结果是相同的。
在这里我们要注意的是要设置一个超级用户,只需要创建一个user表实体,并将全部的属性列值设为Y。user表的权限是全局的,所以并不需要其他授权表中的任何实体。
下面的这个例子创建了三个帐户并且授予他们访问特定数据库的权限。他们中的每一个都是以custom为用户名以obscure为密码。
shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON bankaccount.*
-> TO 'custom'@'localhost'
-> IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON expenses.*
-> TO 'custom'@'whitehouse.gov'
-> IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON customer.*
-> TO 'custom'@'server.domain'
-> IDENTIFIED BY 'obscure';
这三个帐户可以如下面的样子使用:
1 第一个帐户可以访问bankaccount数据库,但是只可以从本地主机进行连接。
2 第二个帐户可以访问expenses数据库,但是只可以从whitehouse.gov主机进行访问。
3 第三个帐户可以访问customer数据库,但是中可以从server.domain主机进行连接访问。
不使用GRANT而设置customer帐户,可以像下面的样子来使用INSERT语句来直接修改授权表:
shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('localhost','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('whitehouse.gov','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('server.domain','custom',PASSWORD('obscure'));
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('localhost','bankaccount','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('whitehouse.gov','expenses','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('server.domain','customer','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
前三个INSERT语句添加了user表实体,允许custom用户可以以指定的密友从各种主机进行连接,但是并没有授予全局权限(所有的权限都设置成为默认的N)。接下来的三个INSERT语句添加了db表实体,为bankaccount,expenses,customer数据库为custom授予权限,但是这要求从合适的主机进行连接。正如平常一样,当我们直接修改授权表时,我们使用FLUSH PRIVILEGES来告诉服务器重新装入,这样这些权限才会生效。
如果我们要指定一个用户可以从一个指定的域进行访问(例如是mydomain.com),我们可以在帐户名的主机部分使用%通配符来执行GRANT语句:
mysql> GRANT ...
-> ON *.*
-> TO 'myname'@'%.mydomain.com'
-> IDENTIFIED BY 'mypass';
如果我们要直接修改授权表来完成同样的事情,我们可以这样来做:
mysql> INSERT INTO user (Host,User,Password,...)
-> VALUES('%.mydomain.com','myname',PASSWORD('mypass'),...);
mysql> FLUSH PRIVILEGES;
限制帐户资源
一个限制服务器资源的方法就是将系统变量max_user_connection设为一个非零值。然而,这个方法更为严格的来说是全局的,而且并不允许对于单个帐户的管理。另外,这个方法只是限制了使用单个帐户同时进行连接的数目,而并不是帐户一旦连接从而进行的操作。这两种类型的控制对于MySQL系统管理员来说都是有趣的,尤其是对于那些为网络服务供应商进行工作的管理员。
在MySQL 5。0中,对于单个帐户我们可以下面的一些服务器资源:
1 每小时每个帐户可以进行查询数目
2 每小时每个帐户可以进行更新数目
3 每小时每个帐户可以与服务器进行连接次数
一个客户端执行的任何语句都属于查询限制。只有修改数据库或是数据表的语句属于更新限制。
从MySQL 5.0.3开始,我们还可以限制基于每一个帐户可以同时与服务器进行连接数目。
在这里所指的一个帐户是指user表中的一个记录。每一个帐户都是由他的User与Host列值所唯一标识的。
使用这个特征的前提是mysql数据库中的user表必须包含与资源相关的列。资源限制的内容存放在max_questions, max_updates,max_connections,max_user_connections列中。如果我们的user表中并没有这些列,那么我们必须进行更新。
使用GRANT语句来设置资源限制,并带要限制的资源名字与每小时数量来表时限制的值的从句。例如,我们创建一个可以访问customer数据库的帐户,但是在有限制的条件下,我们可以执行下面的语句:
mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'
-> IDENTIFIED BY 'frank'
-> WITH MAX_QUERIES_PER_HOUR 20
-> MAX_UPDATES_PER_HOUR 10
-> MAX_CONNECTIONS_PER_HOUR 5
-> MAX_USER_CONNECTIONS 2;
限制的类型并不一定要全部在WITH从句中列出,但是这些列出的内容可以以任何的顺序。每一个每小时的限定值应是一个表示每小数量的整数。如果在 GRANT语句并没有WITH从句,这些限制将会设置成为默认的零值(也就是没有限制)。对于MAX_USER_CONNECTIONS,限制值是一个整数,这个整数用来指明这个帐户在任何时候可以同时连接的连接数。如果这个限制值设置成为默认的零值,max_user_connections系统变量将会用来决定这个帐户同时连接的数目。
要设置或是改变一个已存在的帐户,我们可以在全局级别使用GRANT USAGE语句进行设置。下面的这个将francis的查询限制设置成为100:
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_QUERIES_PER_HOUR 100;
这个语句保持帐户已经存在的权限不变而只修改指定的限制值。
要移除已设置的限制,可以将其设置为零。例如,移除francis每小时可以进行连接数目,我们可以用下面的语句:
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_CONNECTIONS_PER_HOUR 0;
当任何帐户在任何资源使用上有一个非零值限制,资源使用计数才会发生作用。
作为服务器运行,他会计数每一个帐户使用资源的次数。如果一个帐户在最后一个小时内达到了他的连接限制值,那么这个帐户的更多的连接就会被气绝,直到这一个小时结束。相似的,如果一个帐户达到了他的查询或是更新的限制值,那么更多的查询或是更新就会被气绝,直到这一个小时结束。在所有这样的情况下,一个合适的错误信息就会被执行。资源计数是每一个帐户做的,而不是为每一个客户端。例如,如果我们的帐户查询的限制为50,我们并不能通过两个客户端同时与服务器进行连接来达到100。同时连接的查询数会计数在一起。
当前每小时的资源使用数量可以为全部的用户进行全局的重新设置,或者是为每一个用户进行单独设置:
1 要为所用有帐户将当前的计数值设置为零,我们可以执行一个FLUSH PRIVILEGES语句或是一个mysqladmin reload命令)。
2 我们可以通过重新设置一个用户的限制项目来将单个用户的限制值设置为零。要这样做,我们可以使用在前面谈到的GRANT USAGE的方法。
为帐户设置密码
帐户的密码可以通过在命令使用mysqladmin命令来进行设置:
shell> mysqladmin -u user_name -h host_name password "newpwd"
这个设置密码的命令进行设置的帐户是user数据表中匹配User表的user_name与我们进行连接的Host列的值的一个记录。
另一个对一个帐户进行密码设置的方法是执行SET PASSWORD语句:
mysql> SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');
可以像root这样的对mysql数据库有更新权限的用户才可以设置其他帐户的密码。如果我们不是作为匿名用户登陆的,我们可以省略FOR从句来设置我们自己的密码:
mysql> SET PASSWORD = PASSWORD('biscuit');
我们还可以通过在全局级别上使用GRANT USAGE语句来设置一个帐户的密码而不是影响这个帐户当前的权限:
mysql> GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit';
仅管我们更喜欢使用前面所说的方法中的一个来设置用户的密码,但是我们也可以通过直接修改user数据表来进行帐户密码的修改:
1 要在创建新帐户时设置密码,为Password列提供一个值:
shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('%','jeffrey',PASSWORD('biscuit'));
mysql> FLUSH PRIVILEGES;
2 要修改一个帐户的密码,使用UPDATE来设置Password列的值:
shell> mysql -u root mysql
mysql> UPDATE user SET Password = PASSWORD('bagel')
-> WHERE Host = '%' AND User = 'francis';
mysql> FLUSH PRIVILEGES;
当我们使用SET PASSWORD,INSERT,或是UPDATE来设置帐户的密码时,我们必须使用PASSWORD函数来进行加密。(但是如果密码为空时,我们并不需要这样做)。PASSWORD函数是必须的,因为user数据表存放的加密的形式,而不是普通的文本。如果我们忘记了这一点,我们也许会用下面的方法来设置密码:
shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES;
这样的结果就是biscuit会作为密码存放在user数据表中,而不是加密的值。当jeffrey试图使用这个密码与服务器进行连接时,这个值会进行加密,然后与user数据表中存放的值进行比较。然而,存放的是实际的biscuit字符串,所以这样的比较就会失败,而服务器就会拒绝这个连接:
shell> mysql -u jeffrey -pbiscuit test
Access denied
如果我们使用GRANT 。。。IDENTIFIED BY语句或是mysqladmin password命令,他们也会为我们小心的进行密码加密。在这些情况下,PASSWORD函数就不是必须的了。
在这里我们要注意的就是PASSWORD函数的加密与Unix的密码加密不同。