第5章:数据库管理 / 5.7. MySQL访问权限系统 / 5.7.8. 拒绝访问错误的原因

当你试着联接MySQL服务器时,如果碰到问题,下面各项可以帮助你纠正问题:

·         确保服务器在运行。如果服务器没有运行,则你不能连接服务器。如果你视图连接服务器并看到下述消息,可能是服务器没有运行:

·                shell> mysql
·                ERROR 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
  • 必须正确设置授权表,以便服务器可以使用它们进行访问控制。对于某些分发版类型(例如Windows中的二进制分发版或Linux中的RPM分发版),安装过程初始化包含 授权表的mysql数据库。如果分发版没有这样做,你必须运行mysql_install_db脚本来手动初始化授权表。详细内容参见2.9.2节,“Unix下安装后的过程”

确定是否要初始化授权表的一个方法是寻找数据目录下的mysql目录数据目录名通常为datavar,位于MySQL安装目录下。应保证MySQL数据库目录有文件user.MYD。否则,执行mysql_install_db脚本。运行并重启服务器后,执行该命令来测试初始权限:

shell> mysql -u root test

服务器应该让你无误地连接。

  • 在新的安装以后,你应该连接服务器并且设置你的用户及其访问许可:
·                shell> mysql -u root mysql

服务器应该让你连接,因为MySQL root用户初始时没有密码。那也是安全风险,当你正在设置其他MySQL用户时,也应设定root密码是一件重要的事请。关于设置初始密码的说明,参见2.9.3节,“使初始MySQL账户安全”

  • 如果你将一个现存的MySQL安装升级到较新的版本,运行了mysql_fix_privilege_tables脚本吗?如果没有,运行它。增加新功能后,授权表的结构可能会改变,因此更新后应确保表的结构随之更新。相关说明参见2.10.2节,“升级授权表”

·         如果客户端程序试图连接时收到以下错误信息,说明服务器需要新格式的密码,而客户端不能生成:

·                shell> mysql
·                Client does not support authentication protocol requested
·                by server; consider upgrading MySQL client

关于如何处理的详细信息,参见5.7.9节,“MySQL 4.1中的密码哈希处理”A.2.3节,“客户端不支持鉴定协议”

  • 如果你作为root试试连接并且得到这个错误,这意味着,你没有行在user表中的User列值为'root'并且mysqld不能为你的客户端解析主机名:
  • Access denied for user ''@'unknown' to database mysql

在这种情况下,你必须用--skip-grant-tables选项重启服务器并且编辑/etc/hosts\windows\hosts文件为你的主机增加行。

  • 如果你从3.22.11以前的版本更新现存的MySQL安装到3.22.11版或以后版本,你运行了mysql_fix_privilege_tables脚本吗?如果没有,运行它。在GRANT语句变得能工作时,授权表的结构用MySQL 3.22.11修改 。

·         记住客户端程序使用选项文件或环境变量中指定的连接参数。如果客户端程序发送不正确的默认连接参数,而你没有在命令行中指定,检查环境变量和适用的选项文件。例如,当你不用任何选项运行客户端程序,得到Access denied错误,确保你没有在选项文件中指定旧密码!

你可以通过使用--no-defaults选项调用客户端程序来禁用选项文件。例如:

shell> mysqladmin --no-defaults -u root version

客户端使用的选项文件见4.3.2节,“使用选项文件”。环境变量列于附录F:环境变量

·         如果遇到下述错误,说明root密码错误:

·                shell> mysqladmin -u root -pxxxx ver
·                Access denied for user 'root'@'localhost' (using password: YES)

如果你未指定密码时出现前面的错误,说明某个选项文件中的密码不正确。试试前面所说的--no-defaults选项。

关于密码更改的信息参见5.8.5节,“设置账户密码”

如果你丢失或忘记root密码,你可以用--skip-grant-tables重启 mysqld来更改密码。参见A.4.1节,“如何复位根用户密码”.

·         如果你使用SET PASSWORDINSERTUPDATE更改密码,你必须使用  PASSWORD()函数加密密码。如果你不使用PASSWORD()函数,密码不工作。例如,下面的语句设置密码,但没能加密,因此用户后面不能连接:

·                mysql> SET PASSWORD FOR 'abe'@'host_name' = 'eagle';

相反,应这样设置密码:

mysql> SET PASSWORD FOR 'abe'@'host_name' = PASSWORD('eagle');

当你使用GRANTCREATE USER语句或mysqladmin password命令指定密码时,不需要PASSWORD()函数,它们会自动使用PASSWORD()来加密密码。参见5.8.5节,“设置账户密码”13.5.1.1节,“CREATE USER语法”

·         localhost是你本地主机名的一个同义词,并且也是如果你不明确地指定主机而客户端尝试连接的默认主机。

要想在这种系统上避免该问题,你可以使用--host=127.0.0.1选项来明确命名服务器主机。这样将通过TCP/IP协议来连接本地mysqld服务器。你还可以指定--host选项使用TCP/IP,使用实际的本机主机名。在这种情况下,主机名必须指定为服务器主机上的user表行,即使你在服务器上运行客户端程序。

·         当尝试用mysql -u user_name与数据库连接时,如果你得到一个Access denied错误,可能会遇到与user表有关的问题,通过执行mysql -u root mysql并且执行下面的SQL语句进行检查:

·                mysql> SELECT * FROM user;

结果应该包含一个有HostUser列的行匹配你的计算机主机名和你的MySQL用户名。

  • Access denied错误消息将告诉你,你正在用哪个用户尝试登录,你正在试图连接哪个主机,是否使用了密码。通常,你应该在user表中有一行,正确地匹配在错误消息给出的主机名和用户名。例如,如果遇到包含using password: NO的错误信息,说明你登录时没有密码。

·         如果当你试着从一个不是MySQL服务器正在运行的主机上连接时,遇到下列错误,那么在user表中没有匹配那台主机的行:

·                Host ... is not allowed to connect to this MySQL server

可以通过组合你正在试图连接的用户/主机名设置一个账户来修正它。如果你不知道正连接的机器的IP号或主机名,应该把一个'%'行作为Host列值放在user表中。在试图从客户端器连接以后,通过SELECT USER()查询显示你如何真正进行连接。(然后用在日志文件上面显示出的实际的主机名代替user表中的'%'行。否则,你将得到一个不安全的系统,因为它允许从任何主机上以任何用户名连接。)

Linux中,发生该错误的另一个原因可能是你正使用于你所使用版本的glibc库不同版本的库编译的二进制MySQL版本。在这种情况下,你应升级操作系统或glibc,或下载MySQL版本的源码分发版并自己编译。源码RPM一般很容易编译并安装,因此不是大问题。

·         如果你连接时指定主机名,但得到错误消息主机名未显示或为IP号,表示当MySQL服务器将IP号解析为客户端来名时遇到错误:

·                shell> mysqladmin -u root -pxxxx -h some-hostname ver
·                Access denied for user 'root'@'' (using password: YES)

这表示DNS问题。要想修复,执行mysqladmin flush-hosts来重设内部 DNS主机名缓存。参见7.5.6节,“MySQL如何使用DNS”

一些常用的解决方案包括:

o        试试找出DNS服务器的错误并修复。

o        MySQL授权表中指定IP号而不是主机名。

o        /etc/hosts中放入客户端名。

o        --skip-name-resolve选项启动mysqld

o        --skip-host-cache选项启动mysqld

o        Unix中,如果你在同一台机器上运行服务器和客户端,连接到localhost。连接到的localhostUnix连接使用Unix套接字文件而不是TCP/IP

o        Windows中,你在同一台机器上运行服务器和客户端并且服务器支持命名管道连接,连接主机名(周期)。连接使用命名管道而不是TCP/IP

  • 如果mysql -u root test工作但是mysql -h your_hostname -u root test导致Access deniedyour_hostname是本地机的实际主机名,那么在user表中可能没有你的主机的正确名字。这里的一个普遍的问题是在user表行中的Host值指定一个唯一的主机名,但是你系统的名字解析例程返回一个完全正规的域名(或相反)。例如,如果你在user表中有一个主机是'tcx'的行,但是你的DNS告诉MySQL你的主机名是'tcx.subnet.se',行将不工作。尝试把一个行加到user表中,它包含你主机的IP号作为Host列的值。(另外,你可以把一个行加到user表中,它有包含一个通配符如'tcx.%'Host值。然而,使用以%结尾的主机名是不安全的并且推荐!)
  • 如果mysql -u user_name test工作但是mysql -u user_name other_db_name不工作,你没有为给定的用户授予other_db_name数据库的访问权限。
  • 当在服务器上执行mysql -u user_name时,它工作,但是在其它远程客户端上执mysql -h host_name -u user_name时,它却不工作,你没有为给定的用户授予从远程主机访问服务器的权限。
  • 如果你不能弄明白你为什么得到Access denied,从user表中删除所有Host包含通配符值的行(包含%_的条目)。一个很普遍的错误是用Host='%'User='some_user'插入一个新行,认为这将允许你指定localhost从同一台机器进行连接。它不工作的原因是 默认权限包括一个有Host='localhost'User=''的行,因为那个行的Host'localhost''%'更具体,当从localhost连接时,它用于指向新行!正确的步骤是插入Host='localhost'User='some_user'的第2个行,或删除Host='localhost'User=''行。删除条目后,记住用FLUSH PRIVILEGES语句重载授权表。

·         如果你得到下列错误,可以与dbhost表有关:

·                Access to database denied

如果从db表中选择了在Host列有空值的条目,保证在host表中有一个或多个相应的条目,指定db表中的条目适用哪些主机。

·         如果你能够连接MySQL服务器,但如果在使用命令SELECT ... INTO OUTFILELOAD DATA INFILE语句时,你得到Access denied错误,在user表中的条目可能没有启用FILE权限。

·         如果你直接更改授权表(例如,使用INSERTUPDATEDELETE语句)并且你的更改好像被忽略了,记住你必须执行FLUSH PRIVILEGES语句或mysqladmin flush-privileges命令让服务器来重读授权表。否则,直到服务器下次重启,你的更改方有效。记住用UPDATE命令更改root密码后,在清空权限前,你不需要指定新密码,因为服务器还不知道你已经更改了密码!

·         如果你的权限似乎在一个会话过程中改变了,可能是一个超级用户改变了他们。再次装入授权表会影响新客户端连接,但是它也影响现存的连接,如5.7.7节,“权限更改何时生效”小节所述。

·         如果你有PerlPythonODBC程序的存取问题,试着用mysql -u user_name db_namemysql -u user_name -pyour_pass db_name与服务器连接。如果你能用mysql客户端进行连接,这是程序的一个问题而不是访问权限的问题。(注意在-p和密码之间没有空格;也可以使用--password=your_pass语法指定密码。如果使用-p选项MySQL提示你输入密码。)

·         为了测试,用--skip-grant-tables选项启动mysqld守护进程,然后你可以改变MySQL授权表并且使用mysqlaccess脚本检查你的修改是否有如期的效果。当你对你的改变满意时,执行mysqladmin flush-privileges告诉mysqld服务器开始使用新的 授权表。(再次装入授权表覆盖了--skip-grant-tables选项。这允许你告诉服务器开始使用授权表,而不用停掉并重启它)。

·         如果任何其它事情失败,用调试选项(例如,--debug=d,general,query)启动mysqld服务器。这将打印有关尝试连接的主机和用户信息,和发出的每个命令的信息。请参见E.1.2节,“创建跟踪文件”

·         如果你有任何与MySQL授权表的其它问题,而且觉得你必须将这个问题发送到邮件表,一定要提供一个MySQL授权表的倾倒副本(dump)。你可用mysqldump mysql命令复制数据库表。象平时一样,用mysqlbug脚本邮寄你的问题。参见1.7.1.3节,“如何通报缺陷和问题”。在一些情况下可以用--skip-grant-tables重启mysqld以便能运行mysqldump