On Linux, how can I tell how many ephemeral ports are left available?

Is there a method in Linux to check how many ephemeral ports are left available? I occasionally see "Address already in use" errors as a result of running out of ephemeral ports. A machine reboot will resolve this but it would be better to catch it before it happens.


The ephermal port range is specified in /proc/sys/net/ipv4/ip_local_port_range. You can probably extend it to run from 16k to 64k.

You can see the number of open connections using netstat -an. Sockets may be stuck in TIME_WAIT state if you are opening and closing a lot of connections. In some places this is unavoidable, but you may need to consider if you need a pool of connection if this is the case.

If TIME_WAIT is the problem, you can set net.ipv4.tcp_tw_reuse / net.ipv4.tcp_tw_recycle to speed up connection turnover.


Bear in mind that this limit applies per unique (source IP, peer IP, peer port) tuple. Therefore you will need to group the output of netstat/ss by each of these tuples, and check how close each group is to the connection limit.

This post explains how you can do this grouping in more detail. To check how close each group is to the limit in Ruby, you can process ss output like:

#!/usr/bin/ruby

first_port, last_port = IO.read('/proc/sys/net/ipv4/ip_local_port_range').split.map(&:to_i)
ephemeral_port_max = last_port - first_port + 1
ephemeral_port_warning = ephemeral_port_max / 3 * 2

conns = `ss --numeric --tcp state connected "( sport >= :#{first_port} and sport <= :#{last_port} )"`

groups = Hash.new(0)
conns.lines.each do |conn|
  state, recvq, sendq, local, peer = conn.split
  local_ip, local_port = local.split(':')
  group = [local_ip, peer]
  groups[group] += 1
end

groups_requiring_warning =
  groups.select { |k, v| v > ephemeral_port_warning }
  .to_a
  .sort_by { |v1, v2| v1[1] <=> v2[1] } # Sort groups in descending order of number of connections

groups_requiring_warning.each do |group, used_port_count|
  puts "Connections from #{group[0]} to #{group[1]} "\
    "have used #{used_port_count} ephemeral ports out of #{ephemeral_port_max} max"\
    "(#{((used_port_count.to_f / ephemeral_port_max) * 100).round(2)}% used)"
end