localhost vs 127.0.0.1 vs 0.0.0.0
Most of the time, localhost and 127.0.0.1 do the same thing. But they're not technically identical, and the difference matters in specific situations — particularly when dealing with server binding, Docker networking, database connections, and IPv6. And 0.0.0.0 is something else entirely.
The Quick Version
| Address | What It Is | What It Does |
|---|---|---|
localhost | A hostname | Resolves to 127.0.0.1 (IPv4) or ::1 (IPv6) via the hosts file or DNS |
127.0.0.1 | An IPv4 address | The loopback address — always refers to "this computer" |
::1 | An IPv6 address | The IPv6 loopback address — same concept as 127.0.0.1 for IPv6 |
0.0.0.0 | A meta-address | When used for binding: listen on ALL network interfaces (not just loopback) |
When the Difference Matters
1. MySQL "localhost" vs "127.0.0.1"
This is the most common gotcha. MySQL on Linux treats these differently:
localhost→ connects via Unix socket (/var/run/mysqld/mysqld.sock)127.0.0.1→ connects via TCP/IP on port 3306
If MySQL is configured to only listen on the socket (no TCP), connecting to 127.0.0.1 will fail while localhost works. If the socket file is missing or wrong path, localhost fails while 127.0.0.1 works. This is why "MySQL connection refused" is one of the most searched database errors.
# Force TCP connection even with "localhost"
mysql -h 127.0.0.1 -u root -p
# Force socket connection
mysql -h localhost --socket=/var/run/mysqld/mysqld.sock -u root -p
2. Server Binding: 127.0.0.1 vs 0.0.0.0
When you start a development server, the --host flag controls who can access it:
# Only accessible from THIS computer
python -m http.server 8000 --bind 127.0.0.1
# → Only localhost:8000 works
# Accessible from ANY device on the network
python -m http.server 8000 --bind 0.0.0.0
# → localhost:8000 works AND other-device:your-ip:8000 works
This matters constantly in development:
- Testing on your phone: If your dev server binds to 127.0.0.1, your phone can't reach it. Bind to 0.0.0.0 and access it via your computer's local IP (like 192.168.1.100:3000)
- Docker containers: A server inside a container binding to 127.0.0.1 is only reachable inside the container itself. You must bind to 0.0.0.0 for the port mapping (
-p 3000:3000) to work
Framework defaults vary:
| Framework | Default Bind | Access from Network? |
|---|---|---|
| Vite (port 5173) | localhost | No — use --host flag |
| Next.js (port 3000) | 0.0.0.0 | Yes — accessible on network by default |
| Django (port 8000) | 127.0.0.1 | No — use 0.0.0.0:8000 |
| Flask (port 5000) | 127.0.0.1 | No — use --host=0.0.0.0 |
| Rails (port 3000) | 127.0.0.1 (Rails 6+) | No — use -b 0.0.0.0 |
3. IPv6 Resolution
On modern systems, localhost may resolve to ::1 (IPv6) instead of 127.0.0.1 (IPv4). If your server only listens on IPv4, connecting to localhost might fail because your OS tries IPv6 first.
This happens frequently with MySQL, PostgreSQL, and Redis. The fix: use 127.0.0.1 explicitly to force IPv4, or configure the server to listen on both IPv4 and IPv6.
The Hosts File
The mapping from localhost to 127.0.0.1 lives in the hosts file:
| OS | Location |
|---|---|
| Windows | C:\Windows\System32\drivers\etc\hosts |
| Mac / Linux | /etc/hosts |
Typical contents:
127.0.0.1 localhost
::1 localhost
You can add custom entries for local development: 127.0.0.1 myproject.local — then myproject.local resolves to your machine just like localhost.
Summary
- Use
localhostin browser URLs and general access — it's human-readable and works in most cases - Use
127.0.0.1in application configs when you need to guarantee IPv4 TCP connection (especially database connection strings) - Use
0.0.0.0for server binding when you want to accept connections from other devices on your network - Never bind to
0.0.0.0in production without a firewall — it exposes the port to anyone who can reach your server