105

我的 MySQL 数据库需要两个用户:appuser 和 support。
一位应用程序开发人员坚持要我为这些用户创建四个帐户:

appuser@'%'
appuser@'localhost'
support@'%'
support@'localhost'

对于我的生活,我无法弄清楚为什么他认为我们需要这个。不会使用通配符作为主机来处理“本地主机”吗?

有任何想法吗?

(这里使用 MySQL 5.5)

4

6 回答 6

124

localhost在 MySQL 中是特殊的,它意味着通过 UNIX 套接字(或 Windows 上的命名管道,我相信)而不是 TCP/IP 套接字的连接。用作%主机不包括localhost,因此需要明确指定它。

于 2012-05-30T20:35:32.947 回答
35

正如@nos 在对该问题当前接受的答案的评论中指出的那样,接受的答案是不正确的。

是的,当通过套接字连接而不是标准 TCP/IP 连接进行连接时,使用%和用于用户帐户主机之间存在差异。localhost

主机值%不包括localhost套接字,因此如果要使用该方法进行连接,则必须指定。

于 2013-06-13T16:27:36.480 回答
21

让我们测试一下。

以超级用户身份连接,然后:

SHOW VARIABLES LIKE "%version%"; 
+-------------------------+------------------------------+ 
| Variable_name           | Value                        | 
+-------------------------+------------------------------+ 
| version                 | 10.0.23-MariaDB-0+deb8u1-log | 

进而

USE mysql;

设置

创建一个foo带有密码的用户bar进行测试:

CREATE USER foo@'%' IDENTIFIED BY 'bar'; FLUSH PRIVILEGES;

连接

要连接到 Unix 域套接字(即由文件系统条目/var/run/mysqld/mysqld.sock或类似名称命名的 I/O 管道),请在命令行上运行它(使用该--protocol选项确保双重确定)

mysql -pbar -ufoo
mysql -pbar -ufoo --protocol=SOCKET

人们期望上述匹配“用户来自本地主机”,但肯定不是“用户来自 127.0.0.1”。

要从“127.0.0.1”连接到服务器,请在命令行上运行

mysql -pbar -ufoo --bind-address=127.0.0.1 --protocol=TCP

如果您省略--protocol=TCP,该mysql命令仍将尝试使用 Unix 域套接字。你也可以说:

mysql -pbar -ufoo --bind-address=127.0.0.1 --host=127.0.0.1

一行中的两次连接尝试:

export MYSQL_PWD=bar; \
mysql -ufoo --protocol=SOCKET --execute="SELECT 1"; \
mysql -ufoo --bind-address=127.0.0.1 --host=127.0.0.1 --execute="SELECT 1"

(密码在环境中设置,以便传递给mysql进程)

有疑问时的验证

真正检查连接是通过 TCP/IP 套接字还是 Unix 域套接字

  1. 通过检查输出获取mysql客户端进程的PIDps faux
  2. 运行lsof -n -p<yourpid>

你会看到类似的东西:

mysql [PID] quux 3u IPv4 [code] 0t0 TCP 127.0.0.1:[port]->127.0.0.1:mysql (ESTABLISHED)

或者

mysql [PID] quux 3u unix [code] 0t0 [code] socket

所以:

案例 0:Host = '10.10.10.10'(空测试)

update user set host='10.10.10.10' where user='foo'; flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:失败

案例 1:主机 = '%'

update user set host='%' where user='foo'; flush privileges;
  • 使用套接字连接:OK
  • 从 127.0.0.1 连接:好的

案例 2:主机 = 'localhost'

update user set host='localhost' where user='foo';flush privileges;

行为各不相同,这显然取决于skip-name-resolve. 如果设置,将导致localhost根据日志忽略行。在错误日志中可以看到以下内容:“在 --skip-name-resolve 模式中忽略了'user' entry 'root@localhost'。” . 这意味着没有通过 Unix 域套接字进行连接。但这在经验上并非如此。localhost现在仅表示 Unix 域套接字,不再匹配 127.0.0.1。

skip-name-resolve已关闭:

  • 使用套接字连接:OK
  • 从 127.0.0.1 连接:好的

skip-name-resolve开启:

  • 使用套接字连接:OK
  • 从 127.0.0.1 连接:失败

案例 3:主机 = '127.0.0.1'

update user set host='127.0.0.1' where user='foo';flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:好的

案例4:主机=''

update user set host='' where user='foo';flush privileges;
  • 使用套接字连接:OK
  • 从 127.0.0.1 连接:好的

(根据MySQL 5.7: 6.2.4 Access Control, Stage 1: Connection Verification空字符串 '' 也表示“任何主机”,但排序在 '%' 之后。

案例5:Host = '192.168.0.1'(额外测试)

('192.168.0.1' 是我机器的 IP 地址之一,根据您的情况适当更改)

update user set host='192.168.0.1' where user='foo';flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:失败

  • 使用连接mysql -pbar -ufoo -h192.168.0.1:OK (!)

后者是因为这实际上是来自的 TCP 连接192.168.0.1,如下所示lsof

TCP 192.168.0.1:37059->192.168.0.1:mysql (ESTABLISHED)

边缘案例 A:主机 = '0.0.0.0'

update user set host='0.0.0.0' where user='foo';flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:失败

边缘案例 B:主机 = '255.255.255.255'

update user set host='255.255.255.255' where user='foo';flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:失败

边缘案例 C:主机 = '127.0.0.2'

(127.0.0.2 是完全有效的环回地址,等同于RFC6890中定义的 127.0.0.1 )

update user set host='127.0.0.2' where user='foo';flush privileges;
  • 使用套接字连接:FAILURE
  • 从 127.0.0.1 连接:失败

有趣的是:

  • mysql -pbar -ufoo -h127.0.0.2连接自127.0.0.1失败
  • mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2没问题

清理

delete from user where user='foo';flush privileges;

附录

要查看mysql.user表中的实际内容(权限表之一),请使用:

SELECT SUBSTR(password,1,6) as password, user, host,
Super_priv AS su,
Grant_priv as gr,
CONCAT(Select_priv, Lock_tables_priv) AS selock,
CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif,
CONCAT(References_priv, Index_priv, Alter_priv) AS ria,
CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views,
CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv, Event_priv, Trigger_priv) AS funcs,
CONCAT(Repl_slave_priv, Repl_client_priv) AS replic,
CONCAT(Shutdown_priv, Process_priv, File_priv, Show_db_priv, Reload_priv, Create_user_priv) AS admin
FROM user ORDER BY user, host;

这给出了:

+----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
    | password | user     | host      | su | gr | selock | modif | ria | views | funcs | replic | admin  |
    +----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
    | *E8D46   | foo      |           | N  | N  | NN     | NNNNN | NNN | NNN   | NNNNN | NN     | NNNNNN |

同样对于表mysql.db

SELECT host,db,user, 
       Grant_priv as gr,
       CONCAT(Select_priv, Lock_tables_priv) AS selock, 
       CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif, 
       CONCAT(References_priv, Index_priv, Alter_priv) AS ria, 
       CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views, 
       CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv) AS funcs 
       FROM db ORDER BY user, db, host;
于 2018-03-06T18:49:33.160 回答
9

如果user@'%'要从 localhost 连接,请使用mysql -h192.168.0.1 -uuser -p.

于 2013-05-13T08:19:27.373 回答
8

百分号表示:任何主机,包括远程和本地连接。

localhost 只允许本地连接。

(所以首先,如果您不需要远程连接到您的数据库,您可以立即摆脱 appuser@'%' 用户)

所以,是的,它们是重叠的,但是......

...设置两种类型的帐户是有原因的,这在 mysql 文档中进行了解释:http: //dev.mysql.com/doc/refman/5.7/en/adding-users.html

如果您的本地主机上有一个匿名用户,您可以通过以下方式发现:

select Host from mysql.user where User='' and Host='localhost';

如果您只是创建用户 appuser@'%'(而不是 appuser@'localhost'),那么当 appuser mysql 用户从本地主机连接时,将使用匿名用户帐户(它优先于您的 appuser@ '%' 用户)。

对此的解决方法是(正如人们可以猜到的)创建 appuser@'localhost' (这比本地主机匿名用户更具体,如果您的 appuser 从 localhost 连接,则将使用它)。

于 2016-02-04T12:05:02.890 回答
6

将提供与迄今为止提供的答案略有不同的答案。

如果您的 users 表中有来自 localhost 的匿名用户的行,''@'localhost'那么这将被视为比使用通配符 host 的用户更具体'user'@'%'。这就是为什么还需要提供'user'@'localhost'.

您可以在本页底部看到更详细的解释。

于 2015-01-19T04:50:26.207 回答