Stateful vs stateless firewalls, and NGFW explained.
Stateless packet filters judge each packet alone. Stateful firewalls remember the conversation. NGFWs read the payload too. Here's what actually changes at each layer, with a worked example.
"Firewall" is a word that has meant several genuinely different technologies over the last three decades, and most explanations gloss over which one they're actually describing. That matters, because a rule that works perfectly on one type of firewall can be either a security hole or an unnecessary headache on another. The real dividing line isn't "firewall vs no firewall" — it's whether the device evaluating your traffic remembers anything about the connection it's part of. That single distinction is what separates stateless packet filtering from the stateful firewalls almost everyone actually runs today, and it's the foundation everything a next-generation firewall (NGFW) adds sits on top of.
What a firewall actually enforces
At its core, a firewall is a policy engine sitting between two networks (or two zones of the same network) that decides, packet by packet or connection by connection, what may pass and what gets dropped. Every firewall does this by inspecting some combination of: source and destination IP address, source and destination port, and protocol (TCP, UDP, ICMP, and so on). What differs between firewall generations is how much context gets applied to that decision — none, some, or a great deal.
Stateless firewalls — packet filtering with no memory
A stateless firewall, also called a packet-filtering firewall, evaluates every single packet against a static list of rules with zero awareness of what packets came before it or after it. Each packet is a fresh, isolated question: does this source IP, destination IP, port, and protocol combination match an "allow" rule? If yes, it passes; if no, it's dropped. The firewall has no concept of a "connection" at all — only individual packets matching or not matching rules.
This has a real, structural consequence: because the firewall can't recognize a reply packet as belonging to a request that was just sent out, an administrator has to write explicit rules for both directions of every kind of traffic they want to allow. Outbound web browsing needs an outbound rule permitting traffic to port 443, and a separate inbound rule permitting the replies back in — which, since replies arrive on whatever high-numbered port the client happened to pick, usually means opening the entire ephemeral port range rather than one specific port.
- Strengths: extremely fast, low memory and CPU overhead, simple to implement in hardware — this is why they still show up as access control lists (ACLs) on routers and switches.
- Weaknesses: rule sets grow large and error-prone; broad inbound ranges opened to permit "return traffic" can be abused by unsolicited packets that simply claim to come from an allowed port; no ability to distinguish a legitimate reply from a forged one.
Stateful firewalls — tracking the conversation
A stateful firewall solves this by maintaining a state table (sometimes called a connection table): a running record of every connection it has already approved, keyed by the 5-tuple of source IP, source port, destination IP, destination port, and protocol, along with the connection's current state (new, established, or related to an existing one — the terminology Linux's netfilter/conntrack popularized).
When a new outbound connection is initiated and matches an allow rule, the firewall creates an entry in the state table for it. Every subsequent packet — in either direction — that matches an existing entry is automatically permitted, without needing its own explicit rule. A packet claiming to be a reply that doesn't match any table entry gets dropped, no matter what port it claims to be from. This is why a single outbound rule ("allow this network to reach the internet") is usually all that's needed; the firewall handles every return packet itself.
- Strengths: dramatically simpler rule sets, much stronger default posture (nothing gets in that wasn't specifically initiated from inside, or explicitly allowed), the default behind virtually every home router's NAT and every enterprise firewall today.
- Weaknesses: the state table consumes memory and must be maintained per connection, which creates a resource that can be targeted — flooding a firewall with new connection attempts can exhaust its table. It also still only reasons about addresses, ports, and connection state; it has no idea what's actually inside the payload.
Next-generation firewalls (NGFW) — inspecting the payload
An NGFW keeps everything a stateful firewall does and adds visibility into the traffic's content and identity, not just its addressing:
- Deep packet inspection (DPI): looking into the packet payload itself, not just its headers, to identify the actual protocol and content being carried — catching, for example, traffic that's disguised to look like something else on the wire.
- Application awareness: identifying the specific application generating traffic (a video call, a file-sync client, a particular SaaS product) regardless of which port it happens to use, since modern applications increasingly tunnel everything over 443.
- Integrated intrusion prevention (IPS): matching traffic against a database of known attack signatures and behavioral patterns in real time, and blocking matches inline rather than just logging them.
- User and identity awareness: tying rules to authenticated users or groups rather than just IP addresses, which matters enormously once DHCP and mobile devices make IP-to-person mapping unreliable.
- TLS inspection: in enterprise deployments, terminating and re-establishing encrypted connections at the firewall so DPI and IPS can actually see inside traffic that would otherwise be opaque — a capability that carries its own privacy and trust trade-offs.
Commercial NGFW products — Palo Alto Networks' PA-series, Fortinet's FortiGate line, and Cisco Firepower among them — all build on exactly this stack: stateful connection tracking as the base layer, with DPI, application identification, and intrusion prevention layered on top. The same layering shows up in open-source form when a stateful firewall like pfSense is paired with an IPS engine such as Suricata or Snort.
Where a stateful firewall answers "is this connection allowed to exist?", an NGFW additionally answers "what is this connection actually carrying, and does it match something we've decided to block?"
Worked example: one TCP handshake, two firewalls
Suppose an internal client at 10.0.0.15 opens an HTTPS connection to a web server at 203.0.113.50, using ephemeral source port 51823. Here's how the same three-packet handshake gets handled under each model.
Stateless firewall
Rule 1 (outbound, required):
allow src=10.0.0.0/24 dst=any dport=443
Rule 2 (inbound, required to let the reply back in):
allow src=any:443 dst=10.0.0.0/24 dport=1024-65535
Packet 1: 10.0.0.15:51823 -> 203.0.113.50:443 SYN matches Rule 1, passes
Packet 2: 203.0.113.50:443 -> 10.0.0.15:51823 SYN-ACK matches Rule 2, passes
Packet 3: 10.0.0.15:51823 -> 203.0.113.50:443 ACK matches Rule 1, passes
Notice Rule 2: because the firewall has no idea a connection to 203.0.113.50 is actually pending, it has to permit any packet claiming to come from port 443 to any internal host on any ephemeral port. A malicious host anywhere could craft a packet with source port 443 and slip it past Rule 2 even without a real connection ever being requested — the firewall simply can't tell the difference.
Stateful firewall
Rule (outbound, only rule needed):
allow src=10.0.0.0/24 dst=any dport=443
Packet 1: 10.0.0.15:51823 -> 203.0.113.50:443 SYN
-> matches outbound rule, passes, state table gets a new entry:
[10.0.0.15:51823 <-> 203.0.113.50:443, TCP, state=NEW]
Packet 2: 203.0.113.50:443 -> 10.0.0.15:51823 SYN-ACK
-> no matching allow rule needed; matches existing state-table entry, passes
state updated to ESTABLISHED
Packet 3: 10.0.0.15:51823 -> 203.0.113.50:443 ACK
-> matches state-table entry, passes
Unsolicited packet from an unrelated host claiming src port 443,
dst 10.0.0.15:51823, with no prior SYN on record:
-> no matching state-table entry -> dropped, regardless of claimed source port
The stateful firewall needed exactly one rule, and the forged packet gets dropped automatically because it doesn't correspond to any connection the firewall actually saw get initiated. That's the whole advantage in one comparison: the stateless firewall has to trust claimed metadata on every packet; the stateful firewall trusts its own memory of what it already approved.
Comparison at a glance
| Property | Stateless | Stateful | NGFW |
|---|---|---|---|
| What it inspects | Headers, per packet | Headers, per connection | Headers + payload, per connection |
| Memory of past traffic | None | State table per connection | State table + application/signature context |
| Rule complexity | High — explicit rules both directions | Low — mostly outbound rules, replies automatic | Low, plus application/user policies |
| Performance overhead | Very low | Low to moderate | Moderate to high (DPI, IPS, TLS inspection) |
| Vulnerable to | Spoofed packets matching broad inbound rules | State-table exhaustion (SYN floods) | Same as stateful, plus DPI-evasion techniques |
| Typical deployment | Router/switch ACLs, edge filtering | Home routers (NAT), most enterprise firewalls, host firewalls | Enterprise network perimeter, data center edge |
These three layers aren't mutually exclusive alternatives — most real networks run more than one simultaneously. A router's ACLs (stateless) might filter obviously malformed traffic at the very edge before it ever reaches a stateful firewall doing the real connection tracking, which in turn might sit behind or alongside an NGFW doing deep inspection on traffic crossing into a more sensitive zone. Layering them plays to each one's strengths: stateless filtering is cheap and fast for coarse rejection, stateful filtering handles the bulk of legitimate traffic efficiently, and NGFW inspection is reserved for the traffic and zones where its extra cost is actually justified.
Host-based firewalls: the same model on your own machine
Everything above describes network firewalls sitting between networks, but the identical stateful model runs locally on almost every modern operating system, protecting a single host rather than a whole network. Linux uses netfilter, configured through iptables or the newer nftables, both of which maintain their own connection-tracking table (conntrack) exactly analogous to the state table described above. Windows ships with Windows Defender Firewall, and macOS has its Application Firewall plus the underlying pf packet filter inherited from BSD.
# A minimal stateful host firewall in nftables:
# allow established/related traffic back in, drop everything else unsolicited
$ sudo nft add rule inet filter input ct state established,related accept
$ sudo nft add rule inet filter input ct state invalid drop
$ sudo nft add rule inet filter input drop
That first line does precisely what the state table in the worked example above does: ct state established,related tells the kernel to automatically permit any packet matching a connection this host already initiated, without a separate rule needed for the reply direction. Host-based firewalls matter even inside a network that already has a perimeter firewall, because they contain the blast radius if another device on the same network gets compromised — a network firewall alone does nothing to stop lateral movement between two machines already inside it.
Testing your own firewall rules from the outside
The only way to know whether a firewall rule actually does what you intended is to test it from a vantage point outside your own assumptions — ideally from a separate network entirely. A basic port scan against your own public IP shows what's genuinely reachable, regardless of what the rule file says:
# From an external host, scan the most common TCP ports
$ nmap -Pn your.public.ip.address
PORT STATE SERVICE
22/tcp filtered ssh
443/tcp open https
8080/tcp closed http-proxy
open means a service answered the connection — expected for anything you deliberately exposed, like a web server on 443. closed means the host is reachable but nothing is listening on that port, so it was actively rejected. filtered means no response came back at all, which is what a well-configured stateful firewall produces for a port with no matching allow rule: the SYN packet is simply dropped, giving an external attacker no confirmation the host even exists on that port. Seeing "filtered" rather than "closed" on ports you didn't intend to expose is a quick, practical way to confirm your rules are actually doing their job rather than just looking correct on paper.
Where each type still shows up today
Stateless filtering hasn't disappeared — it lives on as fast, cheap ACLs on routers and switches, often used as a coarse first filter before traffic ever reaches a stateful device, precisely because it's so lightweight. Stateful inspection is the default assumption almost everywhere else: your home router's NAT, iptables/nftables with conntrack on Linux, Windows Defender Firewall, and the base layer of essentially every commercial firewall appliance sold today. NGFW capability sits on top of that stateful base at the network perimeter and inside data centers, wherever an organization needs to see what traffic actually is rather than just where it claims to be going — see our hands-on pfSense network segmentation lab for a working example of stateful firewall rules segmenting a real network.
The takeaway
Stateless firewalls filter packets in isolation and need explicit rules for every direction of traffic, which forces broad inbound openings that weaken the model they're supposed to enforce. Stateful firewalls fix that by remembering connections in a state table, letting a single outbound rule implicitly authorize its own return traffic — which is why they became the default almost everywhere. NGFWs build on that stateful foundation and add the ability to actually read what's inside the traffic: application identity, intrusion signatures, and in enterprise settings, the decrypted content itself. None of these layers replaces the others; understanding which one is actually protecting a given network is the first step to configuring it correctly.
