📄 manual_privilege_system.html
字号:
<p>如果你想要初始的权限不同于上面描述的那些,在你运行<code>mysql_install_db</code>之前,你可以修改它。
</p>
<p>为了完全重建权限表,删除在包含<code>mysql</code>数据库的目录下所有<tt>“*.frm”</tt>,<tt>“*.MYI”</tt>和<tt>“*.MYD”</tt>文件。(这是在数据库目录下面命名为<tt>“mysql”</tt>的目录,当你运行<code>mysqld
--help</code>时,它被列出。)然后运行<code>mysql_install_db</code>脚本,可能在首先编辑它拥有你想要的权限之后。
</p>
<p><strong>注意</strong>:对于比<strong>MySQL</strong> 3.22.10旧的版本,你不应该删除<tt>“*.frm”</tt>文件。如果你偶然做了,你应该在运行<code>mysql_install_db</code>之前你的<strong>MySQL</strong>分发中拷回它们。
</p>
<h2><a NAME="Adding_users" HREF="manual_toc.html#Adding_users">6.11 向MySQL增加新用户权限</a></h2>
<p>你可以有2个不同的方法增加用户:通过使用<code>GRANT</code>语句或通过直接操作<strong>MySQL</strong>授权表。比较好的方法是使用<code>GRANT</code>语句,因为他们是更简明并且好像错误少些。
</p>
<p>下面的例子显示出如何使用<code>mysql</code>客户安装新用户。这些例子假定权限根据以前的章节描述的缺省被安装。这意味着为了改变,你必须在<code>mysqld</code>正在运行同一台机器上,你必须作为<strong>MySQL</strong>
<code>root</code>用户连接,并且<code>root</code>用户必须对<code>mysql</code>数据库有<strong>insert</strong>权限和<strong>reload</strong>管理权限。另外,如果你改变了<code>root</code>用户口令,你必须如下的<code>mysql</code>命令指定它。
</p>
<p>你可以通过发出<code>GRANT</code>语句增加新用户: </p>
<pre>shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;
</pre>
<p>这些<code>GRANT</code>语句安装3个新用户:
<dl COMPACT="Adding_users">
<dt><code>monty</code> </dt>
<dd>可以从任何地方连接服务器的一个完全的超级用户,但是必须使用一个口令(<code>'something'</code>做这个。注意,我们必须对<code>monty@localhost</code>和<code>monty@"%"</code>发出<code>GRANT</code>语句。如果我们增加<code>localhost</code>条目,对<code>localhost</code>的匿名用户条目在我们从本地主机连接接时由<code>mysql_install_db</code>创建的条目将优先考虑,因为它有更特定的<code>Host</code>字段值,所以以<code>user</code>表排列顺序看更早到来。</dd>
<dt><code>admin</code> </dt>
<dd>可以从<code>localhost</code>没有一个口令进行连接并且被授予<strong>reload</strong>和<strong>process</strong>管理权限的用户。这允许用户执行<code>mysqladmin
reload</code>、<code>mysqladmin refresh</code>和<code>mysqladmin flush-*</code>命令,还有<code>mysqladmin
processlist</code>。没有授予数据库有关的权限。他们能在以后通过发出另一个<code>GRANT</code>语句授权。
</dd>
<dt><code>dummy</code> </dt>
<dd>可以不用一个口令连接的一个用户,但是只能从本地主机。全局权限被设置为<code>'N'</code>--<code>USAGE</code>权限类型允许你无需权限就可设置一个用户。它假定你将在以后授予数据库相关的权限。
</dd>
</dl>
<p>你也可以直接通过发出<code>INSERT</code>语句增加同样的用户存取信息,然后告诉服务器再次装入授权表:
</p>
<pre>shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
'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;
</pre>
<p>取决于你的<strong>MySQL</strong>版本,对上述,你可能必须使用一个不同数目<code>'Y'</code>值(在3.22.11以前的版本有更少的权限列)。对<code>admin</code>用户,只用在3.22.11开始的版本具有的更加可读的<code>INSERT</code>扩充的语法。
</p>
<p>注意,为了设置一个超级用户,你只需创造一个<code>user</code>表条目,其权限字段设为<code>'Y'</code>。不需要<code>db</code>或<code>host</code>表的条目。
</p>
<p>在<code>user</code>表中的权限列不是由最后一个<code>INSERT</code>语句明确设置的(对<code>dummy</code>用户),因此那些列被赋予缺省值<code>'N'</code>。这是<code>GRANT
USAGE</code>做的同样的事情。 </p>
<p>下列例子增加一个用户<code>custom</code>,他能从主机<code>localhost</code>、<code>server.domain</code>和<code>whitehouse.gov</code>连接。他只想要从<code>localhost</code>存取<code>bankaccount</code>数据库,从<code>whitehouse.gov</code>存取<code>expenses</code>数据库和从所有3台主机存取<code>customer</code>数据库。他想要从所有3台主机上使用口令<code>stupid</code>。
</p>
<p>为了使用<code>GRANT</code>语句设置个用户的权限,运行这些命令: </p>
<pre>shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON bankaccount.*
TO custom@localhost
IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON expenses.*
TO custom@whitehouse.gov
IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON customer.*
TO custom@'%'
IDENTIFIED BY 'stupid';
</pre>
<p>通过直接修改授权表设置用户权限,运行这些命令(注意,在结束时<code>FLUSH
PRIVILEGES</code>): </p>
<pre>shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
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('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
</pre>
<p>头3个<code>INSERT</code>语句增加<code>user</code>表条目,允许用户<code>custom</code>用给定口令从不同的主机进行连接,但是没有授予任何许可(所有权限被设置为缺省值<code>'N'</code>)。后3个<code>INSERT</code>语句增加<code>db</code>表条目,授予<code>custom</code>以<code>bankaccount</code>、<code>expenses</code>和<code>customer</code>数据库权限,但是只能在从正确的主机存取时。通常,在授权表直接被修改时,服务器必须被告知再次装入他们(用<code>FLUSH
PRIVILEGES</code>)以便使权限修改生效。</p>
<p>如果你想要给特定的用户从一个给定的域上的任何机器上存取权限,你可以发出一个如下的<code>GRANT</code>语句:
</p>
<pre>mysql> GRANT ...
ON *.*
TO myusername@"%.mydomainname.com"
IDENTIFIED BY 'mypassword';
</pre>
<p>为了通过直接修改授权表做同样的事情,这样做: </p>
<pre>mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;
</pre>
<p>你也可以使用<code>xmysqladmin</code>、<code>mysql_webadmin</code>甚至<code>xmysql</code>在授权表中插入、改变和更新值。你可以在<strong>MySQL</strong>的<a HREF="http://www.mysql.com/Contrib/">Contrib目录</a>找到这些实用程序。 </p>
<h2><a NAME="Passwords" HREF="manual_toc.html#Passwords">6.12 怎样设置口令</a></h2>
<p>在前面小节的例子里说明了一个重要的原则:当你使用<code>INSERT</code>或<code>UPDATE</code>语句存储一个非空的口令时,你必须使用<code>PASSWORD()</code>函数加密它。这是因为在<code>user</code>表中以加密形式存储口令,而不是作为纯文本。如果你忘记这个事实,你可能像这样试图设置口令:
</p>
<pre>shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password) VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES
</pre>
<p>结果是纯文本值<code>'biscuit'</code>作为口令被存储在<code>user</code>表中。在用户<code>jeffrey</code>试图用这个口令连接服务器时,<code>mysql</code>客户用<code>PASSWORD()</code>加密它并且将结果送给服务器,服务器比较在<code>user</code>表中的值(它是纯文本值<code>'biscuit'</code>)和加密的口令(<em>而不是</em>
<code>'biscuit'</code>),比较失败并且服务器拒绝连接: </p>
<pre>shell> mysql -u jeffrey -pbiscuit test
Access denied
</pre>
<p>因为当他们被插入<code>user</code>表时,口令必须被加密,<code>相反,INSERT</code>语句应该象这样被指定:
</p>
<pre>mysql> INSERT INTO user (Host,User,Password)
VALUES('%','jeffrey',PASSWORD('biscuit'));
</pre>
<p>当你使用<code>SET PASSWORD</code>语句时,你也必须使用<code>PASSWORD()</code>函数:
</p>
<pre>mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');
</pre>
<p>如果你使用<code>GRANT ... IDENTIFIED BY</code>语句或<code>mysqladmin password</code>命令设置口令,<code>PASSWORD()</code>函数是不必要的。他们都考虑到为你加密口令,多以你可像这样指定一个口令<code>'biscuit'</code>:
</p>
<pre>mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';
</pre>
<p>或</p>
<pre>shell> mysqladmin -u jeffrey password biscuit
</pre>
<p>注意: <code>PASSWORD()</code>不是以在Unix口令加密的同样方法施行口令加密。你不应该假定如果你的Unix口令和你的<strong>MySQL</strong>口令是一样的,<code>PASSWORD()</code>将导致与在Unix口令文件被存储的同样的加密值。见<a HREF="manual_Privilege_system.html#User_names">6.2 MySQL 用户名和口令</a>。 </p>
<h2><a NAME="Access_denied" HREF="manual_toc.html#Access_denied">6.13 <code>Access denied</code>错误的原因</a></h2>
<p>当你试着联接<strong>MySQL</strong>服务器时,如果你碰到<code>Access
denied</code>错误,显示在下面的表指出一些你能用来更正这个问题的动作:
<ul>
<li>你是在安装<strong>MySQL</strong>以后运行<code>mysql_install_db</code>的脚本,来设置初始授权表内容吗?如果不是,这样做。见<a HREF="manual_Privilege_system.html#Default_privileges">6.10 设置初始MySQL权限</a>。通过执行这个命令测试初始权限:
<pre>shell> mysql -u root test
</pre>
<p>服务器应该让你无误地连接。你也应该保证你在<strong>MySQL</strong>数据库目录有一个文件<tt>“user.MYD”</tt>。通常,它是<tt>“PATH/var/mysql/user.MYD”</tt>,在此<code>PATH</code>是<strong>MySQL</strong>安装根目录的路径。
</p>
</li>
<li>在一个新的安装以后,你应该连接服务器并且设置你的用户及其存取许可:
<pre>shell> mysql -u root mysql
</pre>
<p>服务器应该让你连接,因为<strong>MySQL</strong> <code>root</code>用户初始时没有口令。既然那也是一个安全风险,当你正在设置其他<strong>MySQL</strong>用户时,设定<code>root</code>口令是一件重要的事请。如果你作为<code>root</code>尝试连接并且得到这个错误:
</p>
<pre>Access denied for user: '@unknown' to database mysql
</pre>
<p>这意味着,你没有一个条目在<code>user</code>表中的一个<code>User</code>列值为<code>'root'</code>并且<code>mysqld</code>不能为你的客库解析主机名。在这种情况下,你必须用<code>--skip-grant-tables</code>选项重启服务器并且编辑你的<tt>“/etc/hosts”</tt>或<tt>“\windows\hosts”</tt>文件为你的主机增加一个条目。
</p>
</li>
<li><a NAME="IDX148"></a>如果你从一个3.22.11以前的版本更新一个现存的<strong>MySQL</strong>安装到3.22.11版或以后版本,你运行了<code>mysql_fix_privilege_tables</code>脚本吗?如果没有,运行它。在<code>GRANT</code>语句变得能工作时,授权表的结构用<strong>MySQL</strong>
3.22.11修改 。 </li>
<li>如果你直接对授权表做修改(使用<code>INSERT</code>或<code>UPDATE</code>语句)并且你的改变似乎被忽略,记住,你必须发出一个<code>FLUSH
PRIVILEGES</code>语句或执行一个<code>mysqladmin flush-privileges</code>命令导致服务器再次读入表,否则你的改变要道下一次服务器被重启时再生效。记住在你设定<code>root</code>口令以后,你将不需要指定它,直到在你清洗(flush)权限以后,因为服务器仍然不会知道你改变了口令!
</li>
<li>如果你的权限似乎在一个会话(session)当中改变了,可能是一个超级用户改变了他们。再次装入授权表作用于新客户连接,但是它也影响现存的连接,如<a HREF="manual_Privilege_system.html#Privilege_changes">6.9 权限改变何时生效</a>小节所述。
</li>
<li>为了测试,用<code>--skip-grant-tables</code>选项启动<code>mysqld</code>守护进程,然后你可以改变<strong>MySQL</strong>授权表并且使用<code>mysqlaccess</code>脚本检查你的修改是否有如期的效果。当你对你的改变满意时,执行<code>mysqladmin
flush-privileges</code>告诉<code>mysqld</code>服务器开始使用新的权限表。<strong>注意:</strong>再次装入授权表覆盖了<code>--skip-grant-tables</code>选项。这允许你告诉服务器开始使用授权表,而不用停掉并重启它。
</li>
<li>如果你有一个Perl、Python或ODBC程序的存取问题,试着用<code>mysql -u
user_name db_name</code>或<code>mysql -u user_name -pyour_pass db_name</code>与服务器连接。如果你能用<code>mysql</code>客户连接,这是你程序的一个问题而不是存取权限的问题。(注意在<code>-p</code>和口令之间没有空格;你也能使用<code>--password=your_pass</code>句法指定口令。)</li>
<li>如果你不能让口令工作,记得如果你用<code>INSERT</code>, <code>UPDATE</code>或<code>SET
PASSWORD</code>语句设置口令,你必须使用<code>PASSWORD()</code>函数。如果你用<code>GRANT
... INDENTIFIED BY</code>语句或<code>mysqladmin password</code>命令指定口令,<code>PASSWORD()</code>函数是不需要的。见<a HREF="manual_Privilege_system.html#Passwords">6.12 怎样设置口令</a>。 </li>
<li><code>localhost</code>是你本地主机名的一个同义词,并且也是如果你不明确地指定主机而客户尝试连接的缺省主机。然而,如果你正在运行于一个使用MIT-pthreads的系统上,连接<code>localhost</code>是不行的(<code>localhost</code>连接使用Unix套接字进行,它没被
MIT-pthreads支持),为了在这样的系统上避免这个问题,你应该使用<code>--host</code>选项明确地命名服务器主机,这将做一个
TCP/IP连接到<code>mysqld</code>服务器。在这种情况下,你必须有在服务器主机上的<code>user</code>表中条目的你真实的主机名。(即使你在服务器同一台的主机上运行一个客户程序,这也是真的。)</li>
<li>当尝试用<code>mysql -u user_name db_name</code>与数据库连接时,如果你得到一个<code>Access
denied</code>错误,你可能有与<code>user</code>桌有关的问题,通过执行<code>mysql
-u root mysql</code>并且发出下面的SQL语句检查: <pre>mysql> SELECT * FROM u
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -