I recently encountered a puzzling scenario on an Ubuntu 12.04 LTS server where MySQL connections worked perfectly with '127.0.0.1' but consistently failed when using 'localhost'. Here's what I discovered and how I resolved it.
The /etc/hosts file appeared correctly configured:
127.0.0.1 localhost
# IPv6 configurations
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Yet services like MySQL, Postfix, and Apache required explicit 127.0.0.1 addresses to function properly.
The issue stems from how different applications handle name resolution:
- Some applications use gethostbyname() which checks /etc/hosts first
- Others may bypass local resolution and try DNS
- MySQL has its own connection method that can be affected by this
MySQL handles 'localhost' specially - it attempts to use Unix domain sockets when you specify 'localhost', while TCP/IP is used for '127.0.0.1'. This explains why one works when the other fails.
// PHP connection examples:
// This might fail:
$link = mysqli_connect('localhost', 'user', 'password', 'database');
// While this succeeds:
$link = mysqli_connect('127.0.0.1', 'user', 'password', 'database');
Here are multiple approaches to resolve this:
1. MySQL Configuration Adjustment
Edit /etc/mysql/my.cnf and ensure:
[mysqld]
bind-address = 127.0.0.1
skip-name-resolve
2. Socket Path Specification
If you prefer to use localhost with sockets:
$link = mysqli_connect('localhost:/var/run/mysqld/mysqld.sock', 'user', 'password', 'database');
3. Hosts File Verification
Ensure no conflicting entries exist:
$ cat /etc/hosts | grep -v '^#' | grep -v '^$'
$ ping -c 1 localhost
$ ping6 -c 1 localhost
On systems with IPv6 enabled, 'localhost' might resolve to ::1 (IPv6 loopback) instead of 127.0.0.1. To test:
$ getent hosts localhost
For most consistent results:
- Use 127.0.0.1 explicitly in your connection strings
- Disable IPv6 if you don't need it (net.ipv6.conf.all.disable_ipv6=1 in /etc/sysctl.conf)
- Consider setting up a specific hostname in /etc/hosts for your MySQL connections
Many developers encounter this puzzling situation where MySQL connections fail when using 'localhost' but work perfectly with '127.0.0.1'. This behavior isn't limited to MySQL - services like Postfix, Apache, and Dovecot may exhibit similar issues.
The primary difference lies in how the system resolves these addresses:
- 'localhost' typically resolves to both IPv4 (127.0.0.1) and IPv6 (::1)
- '127.0.0.1' is strictly IPv4
When MySQL is configured to listen only on IPv4, connections via 'localhost' that resolve to IPv6 will fail.
First verify MySQL's bind address:
grep bind-address /etc/mysql/my.cnf
# Or for newer MySQL versions:
grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf
Test name resolution:
ping localhost
ping6 localhost
getent hosts localhost
Here are several approaches to resolve this issue:
Solution 1: Force IPv4 for MySQL Connections
Add this to your connection string in application code:
// PHP example
$mysqli = new mysqli("127.0.0.1", "username", "password", "database");
# Python example
import mysql.connector
cnx = mysql.connector.connect(user='username', password='password',
host='127.0.0.1',
database='database')
Solution 2: Configure MySQL to Listen on All Interfaces
Edit your MySQL configuration:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Add or modify these lines:
[mysqld]
bind-address = 0.0.0.0
skip-name-resolve
Then restart MySQL:
sudo service mysql restart
Solution 3: Modify Hosts File
Ensure your /etc/hosts contains:
127.0.0.1 localhost
::1 ip6-localhost ip6-loopback
For more persistent cases, check these system settings:
# Check IPv6 status
cat /proc/sys/net/ipv6/conf/all/disable_ipv6
# Test MySQL connection methods
telnet localhost 3306
telnet 127.0.0.1 3306
When setting up new servers, consider these best practices:
- Always test both 'localhost' and '127.0.0.1' during configuration
- Document your MySQL connection method in deployment scripts
- Standardize on either IPv4 or IPv6 throughout your stack