The iptables connection tracking subsystem is failing to keep up, causing legitimate network connections to be dropped and new ones to be rejected with "Too many links" errors. This happens when the system can’t track all the active network connections due to resource exhaustion.

Common Causes and Fixes

  1. nf_conntrack_max is too low:

    • Diagnosis: Check the current maximum connection tracking entries:
      sysctl net.netfilter.nf_conntrack_max
      
      Compare this value to the current number of tracked connections:
      cat /proc/sys/netfilter/nf_conntrack_count
      
      If nf_conntrack_count is consistently close to nf_conntrack_max, this is your problem.
    • Fix: Increase nf_conntrack_max. A common starting point is 1000000 for busy servers.
      sysctl -w net.netfilter.nf_conntrack_max=1000000
      
      To make this permanent, edit /etc/sysctl.conf or a file in /etc/sysctl.d/ and add/modify the line:
      net.netfilter.nf_conntrack_max = 1000000
      
      Then run sysctl -p to apply.
    • Why it works: This directly increases the kernel’s capacity to store connection tracking information, allowing it to handle more concurrent connections.
  2. nf_conntrack_tcp_loose is disabled (for TCP):

    • Diagnosis: Check the current value:
      sysctl net.netfilter.nf_conntrack_tcp_loose
      
      If it’s 0, the system is stricter about TCP state transitions.
    • Fix: Enable nf_conntrack_tcp_loose by setting it to 1:
      sysctl -w net.netfilter.nf_conntrack_tcp_loose=1
      
      Make this permanent by adding to sysctl.conf or a file in sysctl.d/:
      net.netfilter.nf_conntrack_tcp_loose = 1
      
      Apply with sysctl -p.
    • Why it works: When nf_conntrack_tcp_loose is enabled, the connection tracking module is more lenient with TCP state changes. This can help prevent connections from being dropped due to minor TCP state inconsistencies, especially under high load or with network intermediaries that might slightly alter TCP packet timing. It allows the conntrack module to accept packets that might be slightly out of strict TCP sequence but are still part of a valid, albeit imperfectly tracked, connection.
  3. nf_conntrack_tcp_max_retrans is too low (for TCP):

    • Diagnosis: Check the current value:
      sysctl net.netfilter.nf_conntrack_tcp_max_retrans
      
      A low value (default is often 3) might cause connections to be dropped prematurely if TCP retransmissions occur.
    • Fix: Increase nf_conntrack_tcp_max_retrans. A value of 5 or 10 is often sufficient.
      sysctl -w net.netfilter.nf_conntrack_tcp_max_retrans=10
      
      Make this permanent by adding to sysctl.conf or a file in sysctl.d/:
      net.netfilter.nf_conntrack_tcp_max_retrans = 10
      
      Apply with sysctl -p.
    • Why it works: This setting controls how many TCP retransmissions are allowed before the connection is considered dead and removed from the tracking table. Increasing it provides more tolerance for packet loss or network congestion, preventing valid connections from being prematurely terminated and freeing up conntrack entries.
  4. Hash Table Size (nf_conntrack_hashsize) is too small:

    • Diagnosis: The hash table is used to quickly look up connection tracking entries. If it’s too small, lookups become slower, and more entries might collide, potentially leading to dropped packets or inefficient conntrack management. Check the current size:
      sysctl net.netfilter.nf_conntrack_hashsize
      
      If this value is significantly smaller than nf_conntrack_max, it can be a bottleneck. The ideal size is often a power of 2 and roughly proportional to nf_conntrack_max.
    • Fix: Increase nf_conntrack_hashsize. A common recommendation is to set it to a power of 2 that is at least half of nf_conntrack_max. For example, if nf_conntrack_max is 1000000, you might set nf_conntrack_hashsize to 65536.
      sysctl -w net.netfilter.nf_conntrack_hashsize=65536
      
      Make this permanent by adding to sysctl.conf or a file in sysctl.d/:
      net.netfilter.nf_conntrack_hashsize = 65536
      
      Apply with sysctl -p.
    • Why it works: A larger hash table reduces the probability of hash collisions. This means the kernel can find existing connection tracking entries more quickly and efficiently, reducing the load on the conntrack subsystem and preventing it from becoming overwhelmed by lookups.
  5. UDP Connection Tracking Timeout (nf_conntrack_udp_timeout):

    • Diagnosis: UDP is connectionless, but iptables can still track UDP "connections" for a period. If the timeout is too long, idle UDP "connections" can linger in the table, consuming resources. Check the current value:
      sysctl net.netfilter.nf_conntrack_udp_timeout
      
      The default is often 30 seconds.
    • Fix: Decrease nf_conntrack_udp_timeout if you have many short-lived UDP flows. A value of 15 or 30 seconds is typical. If you have very long-lived UDP streams (e.g., some streaming protocols), you might need to increase it, but for general "too many links" issues, reducing it can help clear out stale entries.
      sysctl -w net.netfilter.nf_conntrack_udp_timeout=30
      
      Make this permanent by adding to sysctl.conf or a file in sysctl.d/:
      net.netfilter.nf_conntrack_udp_timeout = 30
      
      Apply with sysctl -p.
    • Why it works: This setting dictates how long a UDP flow will be tracked after the last packet. A shorter timeout means stale UDP flows are removed from the conntrack table more quickly, freeing up memory and reducing the overall count of tracked connections, thus alleviating pressure on the system.
  6. Memory Pressure / Kernel OOM Killer:

    • Diagnosis: If the system is generally low on memory, the kernel’s Out-Of-Memory (OOM) killer might be terminating processes, including network-related daemons or even parts of the networking stack, which can indirectly lead to connection tracking issues. Check dmesg for OOM killer messages:
      dmesg | grep -i oom
      
      Also, monitor overall memory usage with tools like free -h or top.
    • Fix: The fix here is to address the root cause of memory exhaustion, which might involve:
      • Adding more RAM.
      • Optimizing applications to use less memory.
      • Reducing vm.swappiness to discourage excessive swapping.
      • Configuring cgroups to limit memory usage for specific applications.
      • If the issue is specifically with iptables itself consuming too much memory (less common for just tracking limits, more for complex rulesets), consider optimizing your iptables rules.
    • Why it works: By ensuring the system has sufficient available memory, you prevent the OOM killer from interfering with the iptables connection tracking subsystem or other critical processes, allowing it to operate within its configured limits.

After applying these fixes, you might encounter a new error if your iptables rules are excessively complex or if there’s a fundamental network configuration issue, such as a routing loop or a very high rate of malformed packets that the conntrack module is struggling to classify.

Want structured learning?

Take the full Iptables course →