Error Medic

iptables Connection Refused & Packet Loss: Complete Troubleshooting Guide

Fix iptables connection refused and packet loss errors with step-by-step diagnostics, rule auditing, conntrack tuning, and safe rule insertion commands.

Last updated:
Last verified:
2,073 words
Key Takeaways
  • Root cause 1: An explicit REJECT or DROP rule in the INPUT, OUTPUT, or FORWARD chain is blocking traffic before a permissive ACCEPT rule can match — iptables processes rules top-down and stops at the first match.
  • Root cause 2: The nf_conntrack table is full (kernel log shows 'nf_conntrack: table full, dropping packet'), causing the kernel to silently drop new connection attempts and triggering packet loss.
  • Root cause 3: A NAT or MASQUERADE rule is missing or misconfigured in the nat table, breaking return traffic for forwarded connections and appearing as one-sided connection refused errors.
  • Quick fix summary: Run `iptables -L INPUT -n -v --line-numbers` to identify the blocking rule, insert an ACCEPT rule above it with `iptables -I INPUT <line> -p tcp --dport <port> -j ACCEPT`, and for conntrack exhaustion increase `net.netfilter.nf_conntrack_max` via sysctl.
Fix Approaches Compared
MethodWhen to UseTime to ApplyRisk
Insert ACCEPT rule above DROP/REJECTSingle port or IP is blocked by an explicit rule< 1 minLow — surgical, non-destructive
Flush entire chain (iptables -F)Ruleset is corrupted or unknown; need clean slate< 1 minHigh — removes ALL firewall protection
Increase nf_conntrack_max via sysctlKernel logs show 'table full, dropping packet'1–2 minLow — no service restart needed
Replace REJECT with ACCEPT for target portService is intentionally REJECT-ed and needs to be opened< 1 minLow — targeted rule deletion + insertion
Reload from saved ruleset (iptables-restore)Rules have been manually corrupted in a live session1–3 minMedium — depends on saved ruleset quality
Enable connection tracking helpers (nf_conntrack_ftp etc.)Stateful protocols (FTP, SIP) drop packets after handshake2–5 minLow — module-level, reversible

Understanding iptables Connection Refused and Packet Loss

When a client receives Connection refused or experiences packet loss through a Linux host running iptables, the firewall is almost always the first suspect — but the diagnosis requires distinguishing between three fundamentally different failure modes:

  1. REJECT — the kernel actively sends back a TCP RST or ICMP port-unreachable, resulting in an immediate Connection refused.
  2. DROP — the kernel silently discards the packet; the client waits until its TCP timeout expires, producing Connection timed out rather than an instant refusal.
  3. Conntrack table exhaustion — new connections are dropped because the kernel's connection tracking table is full, causing intermittent packet loss that appears as flaky connectivity.

Understanding which failure mode you face determines which fix to apply.


Step 1: Reproduce the Exact Error

Capture the client-side error message before touching any rules. Common forms include:

curl: (7) Failed to connect to 10.0.1.50 port 8080: Connection refused
ssh: connect to host 10.0.1.50 port 22: Connection refused
telnet 10.0.1.50 5432: Connection refused
ERRNO: ECONNREFUSED (111)

An instant Connection refused (ECONNREFUSED) means a REJECT rule is active. A hang followed by Connection timed out (ETIMEDOUT) points to a DROP rule or packet loss. Knowing this narrows your search significantly.


Step 2: Audit the Active Ruleset

Dump all chains with verbose output and line numbers so you can reference exact positions:

# List INPUT chain with packet/byte counters and line numbers
iptables -L INPUT -n -v --line-numbers

# List all tables (filter, nat, mangle, raw)
iptables -L -n -v --line-numbers
iptables -t nat -L -n -v --line-numbers
iptables -t mangle -L -n -v --line-numbers

Look for any rule matching your source IP, destination port, or protocol that has a target of REJECT or DROP. The line number column is critical — you will need it to insert a fix rule above the blocking entry.

Example output indicating a blocked port:

Chain INPUT (policy DROP)
num  pkts bytes target     prot opt in     out     source               destination
1       0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
2      45  2700 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
3       0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 reject-with icmp-port-unreachable

Here line 3 explicitly REJECTs port 8080.


Step 3: Check the Conntrack Table for Exhaustion

If your audit shows no obvious blocking rule but you still see packet loss, check for conntrack exhaustion:

# Check current conntrack table usage vs. maximum
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# Look for kernel drop messages
dmesg | grep -i 'nf_conntrack'
journalctl -k | grep 'nf_conntrack: table full'

If nf_conntrack_count is at or near nf_conntrack_max, that is your packet loss source. The kernel will log:

nf_conntrack: table full, dropping packet

Step 4: Use tcpdump to Verify Packets Are Arriving

Before modifying rules, confirm that packets actually reach the interface:

# Listen on all interfaces for TCP SYN packets to port 8080
tcpdump -i any 'tcp port 8080 and tcp[tcpflags] & tcp-syn != 0' -n

# Also check if RST is sent back (REJECT behavior)
tcpdump -i any 'tcp port 8080' -n

If you see SYN packets arriving but no SYN-ACK in response, iptables is dropping or rejecting them. If you see SYN + RST, a REJECT rule is active.


Step 5: Enable Logging for Precise Rule Identification

Insert a temporary LOG rule immediately before the suspected blocking rule to confirm which rule fires:

# Insert LOG rule at line 3 (before the REJECT at old line 3, now pushed to 4)
iptables -I INPUT 3 -p tcp --dport 8080 -j LOG --log-prefix "IPTABLES-DEBUG-8080: " --log-level 4

# Then test the connection from the client, and watch logs
tail -f /var/log/kern.log | grep IPTABLES-DEBUG
# or
journalctl -f -k | grep IPTABLES-DEBUG

You will see lines like:

Feb 23 14:32:11 myhost kernel: IPTABLES-DEBUG-8080: IN=eth0 OUT= SRC=192.168.1.100 DST=10.0.1.50 PROTO=TCP DPT=8080

This confirms packets are hitting the blocking rule. Remove the LOG rule after diagnosis:

iptables -D INPUT 3

Step 6: Apply the Fix

Fix A — Insert ACCEPT rule above the blocking rule:

# If the REJECT is at line 3, insert ACCEPT at line 3 (pushing REJECT to line 4)
iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPT

# Verify the fix
iptables -L INPUT -n -v --line-numbers

Fix B — Delete the blocking rule entirely:

# Delete by line number
iptables -D INPUT 3

# Or delete by rule specification (safer, avoids line-number drift)
iptables -D INPUT -p tcp --dport 8080 -j REJECT

Fix C — Fix conntrack exhaustion:

# Temporarily increase the limit (immediate effect, lost on reboot)
sysctl -w net.netfilter.nf_conntrack_max=524288

# Make permanent
echo 'net.netfilter.nf_conntrack_max = 524288' >> /etc/sysctl.d/99-conntrack.conf
sysctl -p /etc/sysctl.d/99-conntrack.conf

# Also tune the hashsize for performance
echo 131072 > /sys/module/nf_conntrack/parameters/hashsize

Step 7: Persist the Rules Across Reboots

iptables rules are ephemeral by default. After confirming the fix works, save the ruleset:

# Debian/Ubuntu
iptables-save > /etc/iptables/rules.v4
# Ensure iptables-persistent is installed to reload on boot:
apt-get install iptables-persistent

# RHEL/CentOS/Fedora
service iptables save
# or with firewalld as the manager:
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

Step 8: Validate End-to-End

# From the client, test connectivity
curl -v telnet://10.0.1.50:8080

# Check packet counters on the new ACCEPT rule to confirm traffic is matching
watch -n1 'iptables -L INPUT -n -v --line-numbers'

The pkts and bytes counters on your new ACCEPT rule should increment with each successful connection attempt.


Advanced: Debugging NAT / Forwarding Issues

If the server is acting as a router or NAT gateway and forwarded traffic is refused:

# Verify IP forwarding is enabled
cat /proc/sys/net/ipv4/ip_forward
# Should be 1; enable with:
sysctl -w net.ipv4.ip_forward=1

# Check FORWARD chain
iptables -L FORWARD -n -v --line-numbers

# Check NAT table for MASQUERADE or DNAT rules
iptables -t nat -L -n -v

A missing MASQUERADE rule on the outbound interface means return traffic has no valid source address and is dropped by the destination.

Frequently Asked Questions

bash
#!/usr/bin/env bash
# iptables-diagnose.sh — connection refused / packet loss diagnostic script
# Usage: sudo bash iptables-diagnose.sh <target-port>

PORT="${1:-80}"

echo "=== 1. Chain policies ==="
iptables -L -n | grep -E 'Chain (INPUT|OUTPUT|FORWARD)'

echo "\n=== 2. INPUT chain rules (verbose, line numbers) ==="
iptables -L INPUT -n -v --line-numbers

echo "\n=== 3. OUTPUT chain rules ==="
iptables -L OUTPUT -n -v --line-numbers

echo "\n=== 4. NAT table ==="
iptables -t nat -L -n -v

echo "\n=== 5. Rules matching port ${PORT} ==="
iptables -L -n -v --line-numbers | grep "dpt:${PORT}\|spt:${PORT}"

echo "\n=== 6. Conntrack table usage ==="
echo -n "Current entries: "; cat /proc/sys/net/netfilter/nf_conntrack_count
echo -n "Maximum entries: "; cat /proc/sys/net/netfilter/nf_conntrack_max

echo "\n=== 7. Conntrack exhaustion in dmesg ==="
dmesg | grep -i 'nf_conntrack' | tail -20

echo "\n=== 8. Is the service actually listening? ==="
ss -tlnp | grep ":${PORT}"

echo "\n=== 9. IP forwarding status ==="
cat /proc/sys/net/ipv4/ip_forward

echo "\n=== 10. Active packet drops/rejects on INPUT (non-zero counters) ==="
iptables -L INPUT -n -v --line-numbers | awk '$1 != "0" && /DROP|REJECT/'

echo "\n--- Suggested fixes ---"
echo "Insert ACCEPT before blocking rule (replace LINE_NUM and PORT):"
echo "  iptables -I INPUT LINE_NUM -p tcp --dport ${PORT} -j ACCEPT"
echo ""
echo "Fix conntrack exhaustion:"
echo "  sysctl -w net.netfilter.nf_conntrack_max=524288"
echo "  echo 'net.netfilter.nf_conntrack_max = 524288' >> /etc/sysctl.d/99-conntrack.conf"
echo ""
echo "Fix default DROP policy:"
echo "  iptables -P INPUT ACCEPT"
echo ""
echo "Save rules (Debian/Ubuntu):"
echo "  iptables-save > /etc/iptables/rules.v4"
E

Error Medic Editorial

The Error Medic Editorial team consists of senior DevOps engineers, SREs, and Linux systems administrators with decades of combined experience troubleshooting network, kernel, and infrastructure issues in production environments. Articles are technically reviewed and tested against real systems before publication.

Sources

Related Articles in iptables

Explore More Networking Guides