When examining active connections via netstat -tulnp
, developers often encounter a flood of entries like:
tcp 0 0 localhost:18056 localhost:mysql TIME_WAIT
tcp 0 0 localhost:16683 localhost:mysql TIME_WAIT
This state occurs when the local endpoint initiates connection termination. Each TIME_WAIT connection typically consumes:
- Memory resources (about 1KB per socket)
- Ephemeral port allocation
- Kernel structure overhead
Modern Linux kernels provide several controls through /proc/sys/net/ipv4/
:
# Reduce TIME_WAIT duration (default: 60s)
echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
# Enable socket reuse (critical for high-traffic servers)
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
# Allow recycling sockets in TIME_WAIT state
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
For database connections, implement proper connection pooling. Here's a Python example using SQLAlchemy:
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
engine = create_engine(
'mysql+pymysql://user:pass@localhost/db',
pool_size=20,
max_overflow=10,
pool_recycle=3600,
pool_pre_ping=True
)
Permanent configuration via /etc/sysctl.conf
:
# TIME_WAIT socket recycling
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
# Increase ephemeral port range
net.ipv4.ip_local_port_range = 1024 65535
# Socket buffer optimization
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
For web servers, consider these adjustments:
# Nginx configuration
keepalive_timeout 30;
keepalive_requests 100;
# Apache configuration
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
When monitoring MySQL server connections using netstat
or ss
, you'll frequently encounter numerous sockets stuck in TIME_WAIT state. This isn't a bug - it's a fundamental TCP protocol mechanism designed to:
- Ensure reliable connection termination
- Prevent old duplicate packets from being misinterpreted
- Allow proper cleanup of connection resources
The issue becomes particularly noticeable in MySQL environments because:
# Typical netstat output showing the problem
tcp 0 0 127.0.0.1:54321 127.0.0.1:3306 TIME_WAIT
tcp 0 0 127.0.0.1:54322 127.0.0.1:3306 TIME_WAIT
# ... hundreds or thousands of similar entries
Each TIME_WAIT socket consumes:
- Local port number (limited resource)
- Memory for TCP control block
- Kernel resources
These sysctl settings significantly impact TIME_WAIT behavior:
# /etc/sysctl.conf or runtime adjustment
net.ipv4.tcp_fin_timeout = 15 # Reduce from default 60s
net.ipv4.tcp_tw_reuse = 1 # Allow reusing sockets in TIME_WAIT
net.ipv4.tcp_tw_recycle = 0 # Dangerous in NAT environments (avoid)
net.ipv4.tcp_max_tw_buckets = 20000 # Increase bucket count
net.ipv4.ip_local_port_range = 1024 65535 # Expand ephemeral port range
For MySQL clients, implement connection pooling:
// Python example with connection pooling
import mysql.connector
from mysql.connector import pooling
dbconfig = {
"host":"localhost",
"user":"appuser",
"password":"password",
"database":"appdb"
}
# Create connection pool
connection_pool = mysql.connector.pooling.MySQLConnectionPool(
pool_name="mypool",
pool_size=10,
pool_reset_session=True,
**dbconfig
)
# Usage
def query_data():
connection = connection_pool.get_connection()
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")
# ... process results
cursor.close()
connection.close() # Returns to pool
Modern Linux kernels support PAWS (Protection Against Wrapped Sequences):
net.ipv4.tcp_timestamps = 1 # Enable TCP timestamps
net.ipv4.tcp_rfc1337 = 1 # Protect against TIME-WAIT assassination
Verify your changes with:
# Check current TIME_WAIT count
ss -tan state time-wait | wc -l
# Monitor socket states in real-time
watch -n 1 'ss -s | grep -i time-wait'
# Verify kernel parameters
sysctl net.ipv4.tcp_fin_timeout net.ipv4.tcp_tw_reuse