MySQL Connection Works via localhost But Fails on 127.0.0.1: Debugging TCP/IP vs Socket Connections


2 views

Seeing MySQL accept connections through localhost but reject them via 127.0.0.1 reveals fundamental differences in how MySQL handles connections:

# Working connection (uses Unix socket)
mysql -h localhost -u user -p

# Failing connection (uses TCP/IP)
mysql -h 127.0.0.1 -u user -p

The key distinction lies in MySQL's default connection handling:

  • localhost: Uses Unix domain socket by default (faster, no network stack)
  • 127.0.0.1: Forces TCP/IP connection (subject to network restrictions)

Check your actual connection method with:

# Verify socket connection
mysqladmin -h localhost variables | grep socket

# Verify TCP connection
netstat -ant | grep 3306

When TCP connections fail despite working socket connections:

# Check MySQL's bind address
grep bind-address /etc/mysql/my.cnf

# Test raw TCP connectivity
telnet 127.0.0.1 3306
nc -zv 127.0.0.1 3306

# Verify skip-networking isn't enabled
grep skip-networking /etc/mysql/my.cnf

For applications requiring TCP connections:

# /etc/mysql/my.cnf
[mysqld]
bind-address = 0.0.0.0  # Listen on all interfaces
skip-name-resolve       # Avoid DNS lookups

# For IPv6 support
bind-address = ::

Java connection string adjustment:

jdbc:mysql://127.0.0.1:3306/dbname?useSSL=false&socketFactory=com.mysql.jdbc.NamedPipeSocketFactory

When basic fixes don't work:

# Check for AppArmor/SELinux restrictions
aa-status
getenforce

# Enable MySQL general log
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/var/log/mysql/mysql-general.log';

# Packet capture analysis
tcpdump -i lo -nn -X port 3306

Common causes for this discrepancy:

  • JDBC drivers may enforce TCP when CLI uses sockets
  • Connection pooling libraries with different defaults
  • Firewall rules affecting application users differently
  • MySQL user privileges with host restrictions
# Verify user privileges
SELECT Host, User FROM mysql.user WHERE User = 'your_user';

I recently encountered a baffling MySQL connection issue where connections via localhost worked perfectly, but identical attempts using 127.0.0.1 failed with:

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet'

First, let's verify the basic configuration:

# Check MySQL version
$ mysqld -V
mysqld  Ver 5.5.37-0+wheezy1-log

# Verify bind address
$ grep bind /etc/mysql/my.cnf
bind-address = 127.0.0.1

# Check network connectivity
$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.022 ms

The key difference between these connection methods lies in how MySQL handles them:

  • localhost: Uses Unix domain socket by default
  • 127.0.0.1: Forces TCP/IP connection

To explicitly test socket vs TCP:

# Socket connection
$ mysql --protocol=SOCKET -u user -p

# TCP connection
$ mysql --protocol=TCP -h 127.0.0.1 -u user -p

When TCP connections fail, check these critical points:

# Verify MySQL is listening
$ netstat -tulnp | grep 3306
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN

# Test raw connection
$ telnet 127.0.0.1 3306
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.

For Java applications failing even with localhost, try adding socket explicitly:

jdbc:mysql://localhost:3306/dbname?socketFactory=com.mysql.jdbc.NamedPipeSocketFactory&socket=/var/run/mysqld/mysqld.sock

Or force TCP with connection properties:

jdbc:mysql://127.0.0.1:3306/dbname?useSSL=false&allowPublicKeyRetrieval=true

Enable MySQL query logging temporarily:

SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/var/log/mysql/mysql-general.log';

Check authentication plugins with:

SELECT Host, User, plugin FROM mysql.user;
  1. Modify bind address to include both IPv4 and IPv6:
    bind-address = ::
  2. Add skip-name-resolve to my.cnf
  3. Verify user privileges for both connection methods:
    GRANT ALL PRIVILEGES ON *.* TO 'user'@'localhost' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON *.* TO 'user'@'127.0.0.1' IDENTIFIED BY 'password';