masscan vs nmap: I Timed Both on a 256-Host Range

– min read

Every scanner demo I had read compared nmap and masscan against the same friendly lab box and declared nmap the winner. That is not where the difference lives. The difference shows up when the hosts are mostly not there. So I built a synthetic 256-host range, pointed both tools at it, and timed everything.

Official sites: nmap.org | masscan on GitHub


What you need

  1. Ubuntu 24.04 or 26.04 (I ran this on my homelab runner)
  2. apt install masscan nmap (nmap 7.98, masscan 1.3.2 for this run)
  3. Root, because both tools want raw sockets for SYN scans


The method

The target range is 203.0.113.0/24, which is RFC 5737 documentation space: reserved, non-routable, and safe to blast packets at from anywhere. Nothing answers except one host: I bound 203.0.113.10/32 to my loopback interface and ran a web listener on it, so the range holds 255 dead hosts and one live one. All numbers below come from the runs themselves, not from memory.

First, the listener trick and the scan commands:

ip addr add 203.0.113.10/32 dev lo
python3 -m http.server 8080 --bind 203.0.113.10 &
masscan 203.0.113.0/24 -p22,80,443,8080,3389 --rate=10000 --wait 1


Round 1: the dead /24

masscan tore through 256 hosts x 5 ports in just over ten seconds, and most of that was its fixed response-wait window:

Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2026-11-05 05:02:12 GMT
Initiating SYN Stealth Scan
Scanning 256 hosts [5 ports/host]
rate:  0.07-kpps,  0.55% done,380136:03:53 remaining, found=0
rate:  0.00-kpps, 100.00% done, waiting 0-s

Wall time: 10.64 seconds including the 1 s wait. nmap with its default retry and timeout logic did not finish at all. I had to cut the run at 150 seconds with no result. Only after pinning the retransmit and RTT caps did it complete, and even tuned it took almost thirteen times as long:

masscan 203.0.113.0/24 -p22,80,443,8080,3389 --rate=10000 --wait 1
=> 10.64 s
nmap  -sS -Pn -n -p22,80,443,8080,3389 203.0.113.0/24
=> 150 s, killed, no completion
nmap  -sS -Pn -n -p22,80,443,8080,3389 --max-retries 1 \
      --max-rtt-timeout 2s --initial-rtt-timeout 500ms 203.0.113.0/24
=> 128.77 s

The tuned nmap run reported all five ports as filtered on every dead host. masscan simply sent its packets, waited, and left. For sprawling ranges that is the correct attitude.


Round 2: the live host sweep

Then the result that made me re-run everything. Against the single live host on 10,000 ports, nmap was 26 times faster and found the open ones:

Starting Nmap 7.98 ( https://nmap.org ) at 2026-11-05 04:58 +0000
Nmap scan report for 203.0.113.10
Host is up (0.0000040s latency).
Not shown: 9996 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
8080/tcp open  http-proxy
8899/tcp open  ospf-lite
9090/tcp open  zeus-admin

Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds
masscan 203.0.113.10 -p1-10000 --rate=10000 --wait 1
Scanning 1 hosts [10000 ports/host] ... found=0

masscan reported found=0 on a host with four open ports. The reason: that address is bound to the scanner’s own loopback, and SYN/ACK replies from the local stack never cross the wire masscan sniffs. nmap, which also reads kernel socket state, saw everything. On a genuinely remote host masscan would list those ports too, but this is exactly the trap to know about: scan-from-your-own-box tests flatter nmap and silently break masscan. My first two timings for masscan also included its 10 s default --wait, so I re-ran everything with --wait 1 before trusting the table.


The comparison

Testmasscan 1.3.2nmap 7.98
256 dead hosts, 5 ports10.6 s128.8 s tuned, unfinished at defaults
Live host, ports 1-100004.1 s0.16 s
Open ports found on live host0 (loopback artifact, see above)4
Tuning needed for sane time–rate only3 timeout flags
Host discovery / scripts / OS detectnoyes
Output ergonomicsplain list, grep it yourselfstates, services, XML, NSE


The honest annoying bits: masscan wants root and its own ideas about the network stack, and its progress output is a wall of rate lines you end up grepping anyway. nmap is friendlier until you point it at anything large and dead, where its adaptive timeout logic treats every unresponsive box like a slow host worth retrying.


Verdict

If you are sweeping CIDR blocks you do not control, like internet-wide asset hunting or a big external engagement scope, use masscan: an order of magnitude faster on dead space and it finishes without tuning. If your work is enumerating a known host or a small live set, use nmap: faster there, and it tells you what is actually running. The two tools make a great pipeline: masscan to find which of 65k addresses answer at all, nmap to work up the survivors.

Related on this blog: how I check TLS certificate expiry across a host list, the WireGuard server setup whose ports you might now want to audit, and jq vs Python for the same benchmark-then-argue approach on logs.

masscan vs nmap benchmark wall times
A five-port gigabit Ethernet switch
Photo: www.heimnetzwerke.net, CC BY 4.0, via Wikimedia Commons
Mohamad ZulfahmyCybersecurity · OffSec · Entrepreneur
About me ↗
ON THIS PAGE
On this page