本文将深入解析MySQL中一个常见的配置陷阱:如何确保数据库账号仅允许通过Unix socket进行本地连接,禁止TCP/IP网络访问。许多管理员首先想到的是设置防火墙规则或绑定地址,但事实证明这些方法并不可靠。正确的做法需要同时执行两个关键步骤:使用'localhost'字面量创建账号,并关闭MySQL的TCP监听。

注意:不能仅依赖bind-address或防火墙,必须同时使用'localhost'字面量创建账号并关闭TCP监听,才能实现限制。
为什么MySQL中的'localhost'不是DNS域名,而是Unix socket连接触发器
首先需要理解,MySQL中'localhost'为何被特殊处理为Unix socket连接触发条件,而非简单的DNS域名。MySQL服务端对'localhost'进行了硬编码处理:当用户账号为'u'@'localhost'时,客户端若未指定-h参数或显式使用-h localhost,连接将跳过TCP/IP协议栈,直接尝试Unix socket连接。这一行为并非由配置项控制,也非DNS解析结果——相比之下,'127.0.0.1'、'::1'、'%'等地址均会走TCP连接,即使只监听本地回环接口。
在实际操作中,有几个关键细节需要留意。已有的账号不能直接通过UPDATE mysql.user SET host = 'localhost'来修改——MySQL 8.0+禁止修改Host字段,执行后会导致账号无法使用。必须严格按照步骤先DROP USER 'u'@'old_host',再CREATE USER 'u'@'localhost' IDENTIFIED BY 'pwd'。授权操作必须严格匹配账号的host部分:GRANT SELECT ON db.* TO 'u'@'localhost',对'u'@'%'授权是无效的。另外,一些GUI工具(比如旧版DBeaver)常把localhost自动转成127.0.0.1,这时就需要手动填写socket路径,或者干脆将host字段留空。
如何关闭TCP监听,彻底禁止网络连接
接下来处理网络层面的配置。仅设置bind-address = 127.0.0.1并不足够,它只限制了监听地址,但3306端口依然处于开放状态。要彻底禁用TCP连接,必须启用skip-networking = ON,并将bind-address行注释或删除。
具体操作步骤:编辑/etc/mysql/my.cnf,在[mysqld]段中添加skip-networking = ON。若使用MySQL 8.0+且启用了X Plugin,还需添加mysqlx = 0,防止33060端口被打开。随后重启服务:sudo systemctl restart mysql。验证方法:执行ss -tln | grep :3306应无输出;尝试mysql -h 127.0.0.1 -u u -p应返回Can't connect to MySQL server错误。
确保Unix socket文件路径和权限正确
即便账号和配置均正确,socket文件本身也可能成为障碍。/var/run/mysqld/mysqld.sock文件不存在、目录权限不当或属主不是mysql,都会导致连接失败。因此需要检查真实路径:mysql -u root -p -e "SHOW VARIABLES LIKE 'socket';"。确认socket文件存在:ls -l /var/run/mysqld/mysqld.sock,权限应为srwxrwxrwx。目录/var/run/mysqld/必须存在,属主为mysql,权限为drwxr-xr-x。
客户端连接时,避免使用-h 127.0.0.1,应使用-h localhost或省略-h参数。在应用代码中,仅传递'localhost'作为host并不保险,更可靠的方式是显式指定unix_socket='/var/run/mysqld/mysqld.sock'。
最后,一个极易被忽视的要点:务必删除默认的'root'@'%'或'root'@'127.0.0.1'记录。只要这些记录存在,用户便可通过其他方式绕过限制。在执行DROP/CREATE操作后,建议显式执行FLUSH PRIVILEGES,尤其是在清理权限时。
