Unix vs TCP Sockets

When two processes on the same machine need to talk, they have a choice: use a TCP socket (like talking over the network, even locally) or a Unix domain socket (a file-based IPC mechanism that bypasses the network stack entirely). The difference in performance and security is significant.

What Is a Unix Domain Socket?

How does a Unix socket differ from a regular TCP socket? A TCP socket uses the full networking stack: IP header, TCP header, checksum calculation, loopback interface, even when both endpoints are on the same machine. A Unix domain socket bypasses all of that — data passes directly between kernel buffers without any network protocol overhead. It appears as a special file in the filesystem (type 's' in ls output) and uses standard file permissions for access control.
# Unix sockets appear as files: ls -la /var/run/ # srwxrwxrwx 1 www-data www-data /var/run/nginx.sock ← 's' = socket # srw-rw---- 1 postgres postgres /var/run/postgresql/.s.PGSQL.5432 # Connect to a Unix socket: nc -U /var/run/nginx.sock socat - UNIX-CONNECT:/var/run/nginx.sock # See who's using a Unix socket: ss -xp | grep nginx # u_str LISTEN 0 128 /run/nginx.sock 789 * 0 users:(("nginx",pid=1234,...))

Unix Socket vs TCP — Comparison

Unix Domain SocketTCP Socket (localhost)
Protocol overheadNone — no IP/TCP headersFull TCP/IP stack overhead
LatencyLower (~30% faster for small messages)Higher (loopback still goes through stack)
ThroughputHigher for local IPCLower for local IPC
Access controlUnix file permissions (owner/group/mode)IP-based (any process on machine)
AddressFilesystem path (/var/run/app.sock)IP:port (127.0.0.1:5432)
Cross-machine?No — same host onlyYes — any host
Credential passingYes — can pass UID/GID/PIDNo

Performance Difference

# Benchmark: Unix socket vs TCP (using redis-benchmark as example) # TCP localhost: redis-benchmark -h 127.0.0.1 -p 6379 -t ping # 100000 requests in 0.98 seconds = 102,040 req/sec # Unix socket: redis-benchmark -s /var/run/redis/redis.sock -t ping # 100000 requests in 0.71 seconds = 140,845 req/sec ← ~38% faster # Why? TCP path: # write() → TCP stack → IP stack → loopback → IP stack → TCP stack → read() # Unix socket path: # write() → kernel copy → read() (no protocol processing)

Real-World Usage

Nginx + PHP-FPM

Nginx proxies requests to PHP-FPM via Unix socket for minimum latency. Config: fastcgi_pass unix:/var/run/php/php-fpm.sock; — faster than fastcgi_pass 127.0.0.1:9000.

PostgreSQL

PostgreSQL creates a Unix socket at /var/run/postgresql/.s.PGSQL.5432. Local connections (no host parameter) use it automatically. Faster and uses peer authentication (verify UID without password).

Docker

Docker daemon listens on /var/run/docker.sock. The Docker CLI communicates with it via Unix socket. That's also why mounting this socket into a container gives it full Docker control — be careful with that.

systemd

systemd uses Unix sockets for socket activation — creating the socket before the service starts, so the service inherits it. Also uses them for journald and D-Bus communication.

Credential Passing — A Unique Unix Socket Feature

# Unix sockets can pass authenticated UID/GID/PID via SO_PEERCRED # The kernel fills this — it cannot be forged # PostgreSQL peer authentication uses this: # Client connects via Unix socket # PostgreSQL calls getsockopt(SO_PEERCRED) on the socket # Gets the client's real UID from the kernel # Checks if that UID matches a database user # No password needed — OS already authenticated the user # Example: check peer credentials from a C program: # struct ucred cred; # socklen_t len = sizeof(cred); # getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len); # cred.pid, cred.uid, cred.gid ← verified by kernel # From shell — see who owns a Unix socket connection: ss -xp