Security Groups vs Network ACLs: The Difference That Breaks Your Traffic

Stateful vs stateless, allow-only vs allow-and-deny, instance vs subnet. How AWS security groups and network ACLs really differ, and how to debug them when traffic stops.

AWS gives you two firewalls inside a VPC: security groups and network access control lists (NACLs). They look similar in the console, both have inbound and outbound rules, and both can stop your traffic cold. But they work very differently, and mixing up their behavior is one of the most common causes of mysterious timeouts.

The short version

Security groupNetwork ACL
Attached toNetwork interface (instance, ALB, RDS, Lambda ENI)Subnet
Rule typesAllow onlyAllow and deny
StateStateful: replies are allowed automaticallyStateless: replies must be allowed explicitly
EvaluationAll rules are evaluated togetherRules evaluated in number order, first match wins
DefaultNew SG: deny all inbound, allow all outboundDefault NACL: allow all both ways
Can referenceOther security groupsCIDR ranges only

Security groups: stateful and allow-only

A security group is a firewall around each network interface. Its rules only say what is allowed; anything not allowed is denied. Because it is stateful, if a request is allowed in, the response is automatically allowed out, and vice versa. You never need to think about return ports.

The most powerful feature is that a rule can reference another security group instead of an IP range. For a three-tier app:

  • alb-sg: inbound 443 from 0.0.0.0/0.
  • app-sg: inbound 8080 from alb-sg.
  • db-sg: inbound 3306 from app-sg.

Now any instance in the app tier can reach the database, no matter its IP, and nothing else can. When Auto Scaling replaces instances, the rules keep working because they follow membership, not addresses.

Network ACLs: stateless and ordered

A NACL guards the subnet boundary. Every packet entering or leaving the subnet is checked against the rules in order of their rule number, lowest first, and the first matching rule decides. If nothing matches, the final * rule denies.

Because NACLs are stateless, a request and its response are evaluated separately. That is where the trouble starts.

The ephemeral port trap

When a client connects to your web server on port 443, the client picks a random source port, typically in the range 1024–65535 (the exact range depends on the operating system). Your server replies to that random port. With a security group, the reply is allowed automatically. With a NACL, the subnet's outbound rules must allow traffic to those ephemeral ports, or the reply is dropped and the client sees a timeout.

A correct NACL for a public web subnet therefore looks like this:

Inbound
100  TCP 443        0.0.0.0/0       ALLOW
110  TCP 1024-65535 0.0.0.0/0       ALLOW   (replies to outbound calls)
*    ALL            0.0.0.0/0       DENY

Outbound
100  TCP 1024-65535 0.0.0.0/0       ALLOW   (replies to clients)
110  TCP 443        0.0.0.0/0       ALLOW   (outbound HTTPS calls)
*    ALL            0.0.0.0/0       DENY

Rule order matters

Because the first match wins, a broad allow at rule 100 makes a specific deny at rule 200 useless. Put specific denies first (for example rule 50 denying a known-bad IP range), then the broader allows.

When to use which

  • Use security groups for almost all access control. They are precise, follow your resources and are easier to reason about.
  • Use NACLs as a coarse second layer: blocking a specific IP range at the subnet edge, enforcing that a database subnet never talks to the internet, or meeting a compliance rule that asks for subnet-level controls.
  • Leave the default NACL as "allow all" unless you have a reason to change it. Many outages start with a well-meant NACL "hardening" that forgot ephemeral ports.

Troubleshooting checklist for blocked traffic

  1. Timeout or refused? "Connection refused" usually means the packet arrived and nothing listens on that port. A timeout points to a firewall or routing problem.
  2. Security group of the target: is the port open from the source's IP or security group?
  3. Security group of the source: is outbound traffic allowed? (It is by default, but teams often restrict it.)
  4. NACLs on both subnets: check inbound and outbound, including ephemeral return ports.
  5. Route tables: does each side have a route to the other (local, peering, transit gateway, NAT or internet gateway)?
  6. VPC Reachability Analyzer: it traces the path between two endpoints and tells you exactly which component blocks it.
  7. VPC Flow Logs: REJECT records show which side dropped the packet.

Practice it

The free Cloud Arena lab Security Group vs NACL lets you break and fix both controls in a real AWS account. For a realistic outage, try the incident labs Menu Site Blocked by a Network ACL and Status Page Times Out After the NACL Hardening: each starts broken, and you find and fix the cause.

FAQ

Can a security group deny traffic?

Not explicitly. It only has allow rules; anything not allowed is denied. To block a specific IP while allowing everyone else, use a NACL deny rule (or AWS WAF for HTTP traffic).

Do NACLs apply to traffic inside the same subnet?

No. NACLs only evaluate traffic crossing the subnet boundary. Two instances in the same subnet are only controlled by their security groups.

How many security groups can an instance have?

By default up to five per network interface, and the effective permission is the union of all their rules.

Browse all AWS tutorials · Hands-on AWS labs