AWS Security Group vs NACL: Which One Is Blocking You

Logeshwaran
—

If traffic inside your AWS VPC is timing out, both a security group and a network ACL can be responsible, but you diagnose them differently. A security group protects a resource's network interface, contains allow rules, and is stateful. A network ACL protects a subnet, supports both allow and deny rules, and is stateless. The counterintuitive part is that a perfectly correct inbound rule can still leave a connection dead: with a restrictive NACL, the reply can be blocked on a completely different ephemeral port even though the application port itself is open.

⚡ Quick Answer

• Check the security group first when the resource itself cannot receive the required protocol, port, or source.

• Check the NACL next when the subnet has custom filtering, a DENY rule, or one direction of a connection works while the return traffic fails.

• Security group → stateful, resource/ENI level, allow rules only.

• NACL → stateless, subnet level, allow and deny rules, lowest numbered matching rule wins.

If both appear correct, use Reachability Analyzer and then check routing, load-balancer behavior, the operating-system firewall, and the application. Jump to the troubleshooting order.

Jake runs a small phone shop. His booking page is on AWS, and one Saturday morning it stops loading from the internet. The EC2 instance is running. The application process is running. TCP port 443 appears in the security group.

Jake's question is the question almost everyone eventually asks: "If 443 is allowed, what exactly is still blocking me?"

Start with one packet, not with every VPC setting

The fastest way to get lost in AWS networking is to open the VPC console and start reading every rule you can find.

Instead, define one flow.

Write down these five things:

  1. The source IP address or source resource.
  2. The destination IP address or destination resource.
  3. The protocol, such as TCP, UDP, or ICMP.
  4. The destination port, such as TCP 22, 80, 443, or 5432.
  5. Who initiated the connection.

That last item matters more than it first appears. If a client initiates an HTTPS connection to a server on TCP 443, the return packet is not normally headed back to TCP 443 on the client. It returns to the temporary client port used to create that connection.

Security groups remember the permitted flow. NACLs do not.

Ethan tells Jake, "Do not ask whether 443 is open. Ask whether this exact packet is permitted in both directions by every control it crosses."

That is the mental model for the rest of this page.

Security group vs NACL: the differences that actually cause outages

Characteristic Security group Network ACL
Where it appliesResource / ENI levelSubnet level
Rule actionsAllow onlyAllow and deny
Connection behaviorStatefulStateless
Return trafficAutomatically permitted for an allowed flowMust independently match an allow rule
How rules are evaluatedApplicable rules collectively allow trafficLowest numbered matching rule wins
Explicit denyNoYes
AssociationOne ENI can use multiple security groupsA subnet is associated with one NACL at a time

An ENI is an Elastic Network Interface. In ordinary language, it is the network card AWS gives a resource such as an EC2 instance. Security groups are associated with ENIs, so the security-group layer is much closer to the individual workload than a subnet NACL.

A subnet is a slice of the VPC address range. The NACL associated with that subnet evaluates traffic as it enters or leaves that subnet.

Both layers can matter for the same connection.

🙋‍♂️ Jake's Reality Check

"So if the security group allows 443, the NACL can still kill it?"

Yes. A security-group allow is not a bypass around the subnet NACL.

How a security group blocks a connection

A security group contains permissions. It does not contain a numbered list of ALLOW and DENY rules like a NACL.

If an inbound packet does not match an applicable security-group allow rule, the security group does not admit it.

Suppose an EC2 web server needs HTTPS from the internet. An inbound rule might permit TCP 443 from the intended client range.

Having "HTTPS" somewhere in the rules is not enough. Three parts have to match the packet:

  • The protocol.
  • The destination port.
  • The source.

The source is where many troubleshooting sessions go wrong.

A rule for TCP 443 from 10.0.0.0/16 permits matching private IPv4 sources in that range. It does not permit an unrelated internet client.

A rule that references another security group is different again. It permits traffic based on the private IP addresses of network interfaces associated with that referenced group, in the supported topology.

When somebody tells you "443 is open," mentally translate that into a question:

Open from what source?

Security groups are stateful

If an instance initiates traffic that its security group permits, response traffic for that request can return even if the inbound security-group rules would not independently permit that response.

The same stateful behavior applies in the other direction. If an inbound request is admitted, the response can leave as part of the permitted flow even if the outbound rule set would not independently permit that response packet.

This is why blindly mirroring security-group rules in both directions is not required merely for return traffic.

That does not mean outbound security-group rules never matter. They matter when the protected resource is initiating a new connection.

An application server making a new outbound connection to a database, API, package repository, SMTP server, or another internal workload still needs applicable outbound permission.

Multiple security groups: one allow can be enough

An ENI can have multiple security groups associated with it.

The rules are effectively aggregated for traffic decisions. That means you do not troubleshoot security groups the way you troubleshoot a NACL rule list.

If one attached security group permits TCP 443 from the required source, another attached group does not need a duplicate TCP 443 rule merely to make that same flow work.

This creates a different troubleshooting trap: engineers sometimes inspect the security group they expected to provide access but overlook another group that is actually providing it.

That becomes important before you delete or replace a security group.

Since February 4, 2026, the EC2 and VPC consoles include a Related resources tab for security groups. It gives you a consolidated view of resources that depend on the selected security group.

That is useful when a group is attached to more than the one EC2 instance sitting in front of you. The same group can be relevant to network interfaces associated with other AWS resources too.

⚠️ What this actually breaks

Deleting or tightening a shared security group without checking its dependent resources can interrupt workloads unrelated to the one problem you started troubleshooting.

Security-group references are not copied rules

Security groups can reference another security group as a source or destination in supported configurations.

That does not mean AWS copies the referenced group's own rules into your group.

Imagine:

sg-app allows TCP 3306 from sg-web.

That means network interfaces associated with sg-web can be accepted as the source for that rule when the connection and topology support the reference.

It does not mean every CIDR allowed by sg-web becomes a source of sg-app.

This distinction matters when somebody says, "But that first security group already allows my laptop."

Being allowed into the referenced group is not the same thing as belonging to the referenced group.

VPC peering references

For peered VPCs, same-Region security-group references can be used when the requirements are met.

If the peer VPC belongs to another AWS account in the same Region, the owner information is relevant when specifying the referenced security group.

Cross-Region VPC peering is different. You use CIDR-based rules rather than a cross-Region security-group reference.

The route tables still need routes for the peering connection. A security-group reference is permission, not routing.

Transit Gateway references

Security-group referencing can also operate across VPCs attached to the same transit gateway when the feature is enabled in the required places.

There is an important asymmetry: Transit Gateway security-group referencing supports inbound-rule references, not outbound-rule references.

If Reachability Analyzer reports SG_REFERENCING_SUPPORT, inspect whether security-group referencing support is enabled for both the transit gateway and the relevant VPC attachment.

If it reports SG_REFERENCES_NOT_PRESERVED, a component in the forwarding path is discarding the security-group identity that the rule depends on.

Stale security-group rules: the reference exists on paper, not in reality

A referenced security-group rule can become stale.

One example is a rule referring to a security group in a peered or shared VPC when the referenced group is deleted or the relevant peering relationship is deleted.

The rule may still be visible, but it no longer describes a valid reachable relationship.

That is a subtle failure mode because the rule looks more legitimate than a missing rule. The ID is there. The port is there. The source appears to be there.

When cross-VPC traffic stops after infrastructure cleanup, migration, or a peering change, check for stale references rather than repeatedly recreating the target application's port rule.

How a NACL blocks traffic

A network ACL behaves more like an ordered packet filter.

Every rule has a number. AWS starts with the lowest numbered rule and moves upward until it finds the first rule that matches the packet.

That matching rule decides whether the packet is allowed or denied.

Processing stops there.

A later allow rule cannot rescue a packet that already matched an earlier deny rule.

Rule Protocol / port Source Action
50TCP 443203.0.113.0/24DENY
100TCP 4430.0.0.0/0ALLOW
*AllAll unmatched trafficDENY

A client at 203.0.113.25 matches rule 50 first. Its HTTPS traffic is denied.

Rule 100 never gets the opportunity to allow that packet.

This is why "I have an ALLOW for 443" is incomplete when discussing NACLs.

The correct question is:

What is the first rule that matches this exact packet?

The NACL return-path problem that looks like a broken application

NACLs are stateless.

If they allow an inbound packet, that fact is not remembered when the response packet leaves.

Consider this HTTPS connection:

203.0.113.25:51742 → 10.0.1.20:443

The server receives traffic destined for TCP 443.

The response is:

10.0.1.20:443 → 203.0.113.25:51742

The destination port on the return packet is 51742, not 443.

If your outbound NACL only allows TCP 443, the response can still be rejected.

⚠️ What this actually breaks

A public web server can accept an inbound HTTPS packet and still appear completely dead to the browser if its NACL blocks the outbound response to the client's ephemeral port.

This failure feels strange because the server's well-known port is correct. The mistake is on the other half of the flow.

Ephemeral ports: there is not one magic range for every client

The initiating client chooses a temporary source port. The available ephemeral range depends on the client or AWS component involved.

Client / component Relevant ephemeral range Why it matters
Many Linux kernels, including Amazon Linux32768-61000Common for instance-originated TCP connections
Windows Server 2008 and later49152-65535Useful when the remote client is modern Windows
Older Windows through Server 20031025-5000Relevant to legacy systems
Elastic Load Balancing1024-65535Broad range can be needed in NACL designs involving load balancers
NAT Gateway1024-65535NAT can remap source ports
AWS Lambda1024-65535Relevant when Lambda initiates traffic into a controlled path

A common broad rule for public-facing workloads is 1024-65535 where the architecture requires support for many client types, but do not turn that into a superstition.

The better rule is: identify the initiating system and allow the return path that system requires.

AWS's own custom-NACL example uses 32768-65535 for certain public web-server return traffic, while other examples use 1024-65535 when the initiating client or component can use the broader range.

Ethan tells Jake, "Ephemeral ports are not a second application port. They are where the client is waiting for the answer."

Default NACL and custom NACL do not start the same way

The default NACL that comes with a VPC has numbered rules allowing IPv4 traffic in both directions. If the VPC has IPv6, corresponding IPv6 allow rules are present as applicable.

Below those rules is the asterisk rule that denies unmatched traffic.

A newly created custom NACL starts differently. Until you add rules, inbound and outbound traffic falls to its default deny behavior.

🙋‍♂️ Jake's Reality Check

"I created a new NACL and associated it before adding the rules. Why did the whole subnet go quiet?"

Because a fresh custom NACL is not a clone of the default NACL. Build the required rule set before using it on live subnet traffic.

The * rule cannot be removed. It acts as the final deny for anything your numbered rules did not match.

NACL rule numbers: lower means earlier, not less important

NACL rule numbers can range from 1 through 32766 for normal numbered rules.

The lower number is evaluated first.

Use gaps between rule numbers. For example:

100, 200, 300, 400

That leaves room for an emergency rule at 150 without forcing you to redesign the whole numbering sequence.

This matters because changing precedence means changing the rule number.

With command-line or API workflows, NACL rules are added and deleted rather than edited in place. In the console, the editing experience can handle replacement for you, but the underlying ordering rule is still the same.

The troubleshooting order that prevents random firewall changes

Use this order when a VPC connection fails.

  1. Write the flow. Source, destination, protocol, destination port, and initiator.
  2. Confirm DNS resolution. Make sure the hostname resolves to the address you think you are testing.
  3. Identify the destination ENI. Confirm which security groups are actually associated with it.
  4. Check security-group ingress. Does an applicable rule permit the exact source and port?
  5. Check security-group egress if the resource initiates the connection.
  6. Identify the source and destination subnets.
  7. Identify the NACL associated with each relevant subnet.
  8. Check NACL inbound rules in numerical order.
  9. Check NACL outbound rules in numerical order.
  10. Trace the return packet and its ephemeral destination port.
  11. Check the relevant route tables.
  12. Check internet gateway, NAT gateway, peering, Transit Gateway, VPN, or other path components as applicable.
  13. Run Reachability Analyzer for a supported source and destination.
  14. Use Flow Logs to compare accepted and rejected traffic.
  15. Only then move into the operating system and application.

✅ Why this is the one to use

It narrows the failure to one layer without weakening controls that were already correct. A troubleshooting change should teach you something about the failing packet, not simply make the network wider.

Console route: find the security group that actually protects the resource

  1. Open the Amazon EC2 or VPC console.
  2. Open Security groups.
  3. Select the security group associated with the destination network interface.
  4. Review Inbound rules.
  5. Match the protocol, port, and source to the packet you wrote down.
  6. Review Outbound rules when the protected resource initiates a new connection.
  7. Open Related resources before deleting, replacing, or heavily tightening a security group that may be shared.

A useful test is to read the rule aloud:

"This permits TCP 443 from this source."

If you cannot fill in the source accurately, you have not finished checking the rule.

Do not temporarily use 0.0.0.0/0 for SSH just because a timeout is annoying. A troubleshooting step that exposes TCP 22 to the internet can create a security problem while telling you less than a precise source rule would.

Console route: identify the NACL associated with the affected subnet

Open the VPC console and choose Network ACLs.

Before reading the rules, confirm the ACL is associated with the subnet that carries the traffic you are troubleshooting.

Then inspect inbound rules.

Start with the smallest rule number and ask whether each rule matches:

  • The protocol.
  • The source CIDR.
  • The destination port range.

Stop at the first match.

Then repeat the process for the response packet in the outbound rules.

If the instance initiated the connection, the return packet direction is reversed: the response comes back through the subnet's inbound NACL rules toward the client's ephemeral port.

That single direction change explains why copied inbound/outbound rule sets can be wrong even when they look nicely symmetrical.

CLI route: inspect the exact rules without clicking around

To inspect individual security-group rules:

aws ec2 describe-security-group-rules \
  --filters Name=group-id,Values=sg-0abcdef1234567890

Inbound only:

aws ec2 describe-security-group-rules \
  --filters Name=group-id,Values=sg-0abcdef1234567890 \
  --query 'SecurityGroupRules[?IsEgress==`false`]'

Outbound only:

aws ec2 describe-security-group-rules \
  --filters Name=group-id,Values=sg-0abcdef1234567890 \
  --query 'SecurityGroupRules[?IsEgress==`true`]'

To inspect a network ACL:

aws ec2 describe-network-acls \
  --network-acl-ids acl-0abcdef1234567890

Inbound NACL entries:

aws ec2 describe-network-acls \
  --network-acl-ids acl-0abcdef1234567890 \
  --query 'NetworkAcls[*].Entries[?Egress==`false`]'

Outbound NACL entries:

aws ec2 describe-network-acls \
  --network-acl-ids acl-0abcdef1234567890 \
  --query 'NetworkAcls[*].Entries[?Egress==`true`]'

To show NACLs and their associated subnets inside a VPC:

aws ec2 describe-network-acls \
  --filters Name=vpc-id,Values=vpc-1234567890abcdef0 \
  --query 'NetworkAcls[*].{ACL:NetworkAclId,Subnets:Associations[].SubnetId}'

If peered or Transit Gateway-connected VPCs use security-group references, this command helps identify external VPCs referencing your groups:

aws ec2 describe-security-group-references \
  --group-id sg-0abcdef1234567890

Reachability Analyzer can tell you which layer breaks the path

Reachability Analyzer performs static configuration analysis for supported VPC paths.

Static means it analyzes the configured network path rather than sending a real test packet through your application.

If the destination is reachable, it shows the virtual path.

If the destination is not reachable, it can identify the component preventing the path.

Several explanation codes are especially useful here.

Explanation code Meaning for your troubleshooting
ENI_SG_RULES_MISMATCHThe security-group rules do not admit the analyzed traffic.
SG_HAS_NO_RULESThe relevant security group has no inbound or outbound rules for the context being analyzed.
SUBNET_ACL_RESTRICTIONThe subnet's NACL does not admit the required traffic.
NO_ROUTE_TO_DESTINATIONThere is no applicable route to the destination.
SG_REFERENCING_SUPPORTTransit Gateway security-group referencing support is missing where the path requires it.
SG_REFERENCES_NOT_PRESERVEDA forwarded path no longer preserves the security-group identity needed by a referenced-group rule.
REMAP_EPHEMERAL_PORTA NAT gateway or load balancer remaps a source port into the ephemeral range.

This turns a broad "AWS networking is broken" complaint into a much smaller problem.

If the analyzer says SUBNET_ACL_RESTRICTION, there is little value in widening the instance's security group.

If it says NO_ROUTE_TO_DESTINATION, opening both firewalls will not manufacture a route.

Use VPC Flow Logs to see ACCEPT and REJECT behavior

VPC Flow Logs record metadata about IP traffic going to and from supported network interfaces and VPC resources.

The action field can show ACCEPT or REJECT.

A rejection tells you that the traffic was not admitted by the applicable network controls, but a basic flow record is not a magical pointer to one exact rule number.

Use direction and timing.

If the incoming SYN is rejected, investigate the security-group ingress and NACL ingress for that path.

If the request is accepted but return traffic is rejected, the NACL return path becomes a strong suspect.

If the network flow is accepted but the client still receives no useful application response, move higher in the stack: listener, operating-system firewall, process binding, TLS configuration, health status, or the application itself.

A firewall permission does not create a route

A route table answers a different question from a security group or NACL.

A firewall rule asks: "May this traffic pass?"

A route asks: "Where should this destination go?"

You need both.

An instance in a private subnet may have a security group that permits all outbound traffic and a permissive NACL. It still cannot use a NAT gateway that its subnet route table does not point to.

A peered VPC can have perfect security-group rules in both VPCs. Without the required peering routes, packets do not reach the peer.

A Transit Gateway path can fail because an attachment, route table association, propagation, or destination route is missing even though both firewall layers look correct.

🙋‍♂️ Jake's Reality Check

"Can I temporarily allow all traffic in the security group and NACL to prove the network is okay?"

Not necessarily. A missing route remains missing, while your troubleshooting change has unnecessarily widened the network.

Same-subnet traffic changes which control deserves your attention

NACLs evaluate traffic as it enters or leaves a subnet.

Traffic routed within the same subnet is therefore different from traffic that crosses a subnet boundary.

If two EC2 instances live in the same subnet and cannot communicate, do not begin with an elaborate theory about a NACL return-path failure.

Check the destination security group and application listener first.

If they are in different subnets, both subnet boundaries and their NACL associations become relevant to the path.

A quick way to split the two cases is a plain TCP test from the source instance, such as nc -vz 10.0.1.25 5432. "Connection refused" means the packet arrived and nothing was listening. A timeout inside one subnet points at the destination security group or at a firewall on the instance itself, such as iptables or Windows Defender Firewall, which neither AWS control can see.

IPv4 working does not prove IPv6 works

IPv4 and IPv6 rules are separate.

0.0.0.0/0 means all IPv4 addresses.

::/0 means all IPv6 addresses.

A hostname can return both address families. A client may choose IPv6 even though the engineer only checked IPv4 rules.

Security-group quota accounting also treats IPv4 and IPv6 rules separately for the default inbound/outbound rule quotas.

NACL rule sets must likewise contain the IPv6 entries your architecture requires.

If a service works when you manually connect to its IPv4 address but fails through a dual-stack hostname, compare the IPv6 security-group rules, NACL rules, and IPv6 routes before blaming the application.

Load balancers create more than one network leg

A request through a load balancer is not one simple client-to-instance packet path.

There is a client-facing leg and a load-balancer-to-target leg.

Your target's security group should be written for the traffic the target actually receives.

The NACLs on the load-balancer subnets and target subnets must permit the traffic required by that architecture.

Elastic Load Balancing can use the broad 1024-65535 ephemeral range, which matters when you create restrictive NACLs.

A custom NACL can also break load-balancer health checks. If backend instances live behind a restrictive ACL that denies the load balancer's required traffic, targets can become unhealthy even while the application itself is running.

Reachability Analyzer has load-balancer-specific explanation codes for listener, target, Availability Zone, and ACL restrictions. A firewall comparison article that ignores the load balancer can therefore send you to the wrong layer.

NAT Gateway paths: the original source port may not survive

NAT gateways can remap source ports.

The ephemeral range relevant to NAT Gateway translation is 1024-65535.

That matters when you build restrictive NACL rules around private workloads that initiate internet connections through a NAT gateway.

Do not assume the port visible at one side of the path remains identical on the other side.

If Reachability Analyzer reports REMAP_EPHEMERAL_PORT, account for that translation when reasoning about the return path.

The practical rule: the NACL on the NAT gateway's own public subnet must allow inbound replies on 1024-65535, because the translated port can land anywhere in that range, even when your instances only use the Linux default of 32768-60999. Jake's first locked-down NACL allowed only the Linux range, and package downloads failed about one time in three, which is exactly the pattern a partial port mismatch produces.

RDS connection timeouts: security-group source mistakes are common

Suppose an application server must reach an RDS database on TCP 5432.

A clean design can allow the database security group to receive TCP 5432 from the application's security group.

That is usually easier to maintain than repeatedly adding application instance IP addresses.

If the connection fails, ask:

  • Is the application instance actually associated with the referenced source security group?
  • Does the RDS network interface use the security group you are inspecting?
  • Does the application's outbound security group permit the new connection if egress has been restricted?
  • Do the subnet NACLs permit the path and return traffic?
  • Does DNS resolve the RDS endpoint to the expected reachable addresses?
  • Is routing between the relevant subnets and VPCs correct?

A database security group referencing sg-app does not mean "allow anything that sg-app itself allows." It means allow traffic from network interfaces associated with that group in the supported path.

Current VPC firewall quotas that can become troubleshooting problems

As of October 2026, the default VPC security-group quota is 2,500 security groups per Region.

The default rule quota is 60 inbound rules and 60 outbound rules per security group. IPv4 and IPv6 are enforced separately for that quota.

The default number of security groups per network interface is 5, adjustable up to 16.

The product of the rules-per-security-group quota and security-groups-per-network-interface quota cannot exceed 1,000.

For NACLs, the current default is 20 inbound rules and 20 outbound rules per network ACL, including the default deny rules. That quota is adjustable up to 40 per direction, although increasing it can affect network performance.

Quota Default Troubleshooting relevance
VPC security groups per Region2,500Large environments can accumulate many groups and dependencies.
Inbound or outbound rules per security group60 per directionA design that adds one CIDR rule per client can eventually hit quota.
Security groups per ENI5Multiple attached groups make manual rule tracing harder.
Inbound rules per NACL20Includes the default deny rule.
Outbound rules per NACL20Complex deny lists can consume rules quickly.

Worked quota example

Suppose a security group already contains 56 IPv4 inbound rules.

Under the default quota of 60, it has room for:

60 - 56 = 4

four additional IPv4 inbound rules.

If somebody proposes adding 15 new individual client CIDRs, that plan does not fit under the current default.

A customer-managed prefix list can simplify some rule management, but remember that prefix-list entries count against security-group rule capacity according to the prefix list's maximum size. It is not a way to turn hundreds of entries into a free one-rule quota slot.

Do security groups or NACLs add a direct firewall charge?

Security groups and network ACLs do not carry a separate usage charge simply for having and using those controls.

That does not mean the surrounding network architecture is free.

NAT gateways, data transfer, Transit Gateway, load balancers, Flow Logs destinations, and other services in the path can have their own charges.

The firewall question and the billing question are therefore separate.

Do not remove a required control because somebody believes the rule itself is creating a per-packet firewall bill.

If you want to see where VPC money really goes, open Cost Explorer, group by usage type, and look for entries ending in NatGateway-Hours, NatGateway-Bytes and DataTransfer. Those lines, not the rules on the security group, are what a network review should cut first.

Symptom-first decision table: what should you inspect next?

Symptom First place to look Then check
SSH from your laptop times outSecurity-group TCP 22 sourceNACL, route, public-address path, OS firewall, SSH service
Port is allowed but reply disappearsNACL return pathEphemeral port range and routing
Only one subnet failsThat subnet's NACL and route tableResource SG and Availability Zone-specific path components
Problem started after custom NACL associationCustom NACLBoth directions and rule order
Higher-number ALLOW seems ignoredLower-number NACL ruleFirst matching rule
Cross-VPC SG reference stopped workingPeering/TGW relationship and stale SG referenceRoutes and reference support
Load balancer says target unhealthyTarget SG and subnet NACLListener, target port, health-check path
IPv4 works but hostname failsDNS answer and IPv6 rulesIPv6 NACL and route
Both firewall layers look openReachability Analyzer / routeOS firewall, process listener, application

Seven mistakes that make the wrong firewall look guilty

1. Checking the right rule in the wrong security group.

Resource changes can leave you staring at a group that is no longer attached to the active ENI.

2. Checking the right NACL on the wrong subnet.

Confirm the subnet association before analyzing rule order.

3. Treating a referenced security group as a copied set of CIDR blocks.

It is a reference to resources associated with that group, not a recursive import of its rules.

4. Opening only the service port in both directions of a NACL.

Return packets may target ephemeral ports, not the well-known service port.

5. Forgetting IPv6.

A dual-stack hostname can take a path your IPv4-only rules never considered.

6. Assuming permission means reachability.

A missing route cannot be fixed with a wider security rule.

7. Blaming AWS networking after the packet reaches the instance.

If the network layer admits the packet but nothing is listening on the destination port, the application still fails.

When neither security group nor NACL changes fix the problem

If Reachability Analyzer shows a reachable path and Flow Logs show the expected traffic being accepted, stop treating the VPC firewall as the only possible cause.

Check whether the operating system is listening:

ss -lntp

On a Linux host, that can help identify listening TCP sockets.

Check whether the application bound itself to 127.0.0.1 instead of an address reachable through the instance interface.

Check the host firewall.

Check the load-balancer listener and target port.

Check target health.

Check TLS configuration if the TCP connection establishes but HTTPS negotiation fails.

Check DNS if different clients reach different addresses.

Check whether the client is really testing the same Region, account, VPC, endpoint, and address you are inspecting.

For an AWS Support case, gather:

  • Source and destination IP addresses.
  • Protocol and port.
  • Approximate failure timestamp.
  • VPC and subnet IDs.
  • Source and destination ENI IDs where applicable.
  • Security-group IDs.
  • NACL IDs.
  • Relevant route table IDs.
  • Reachability Analyzer result.
  • Relevant Flow Log records.
  • The exact client error.

"EC2 cannot connect" is a hard problem description.

"TCP from 10.0.1.15:51822 to 10.0.4.90:5432 is rejected at the destination subnet at 10:42 UTC" is something an engineer can work with.

AWS security group vs NACL FAQ

How do I know if a security group or NACL is blocking traffic?

Define the source, destination, protocol, port, and connection initiator. Check the destination security group first, then the NACL associated with each relevant subnet in both directions. For supported paths, Reachability Analyzer can identify security-group rule mismatches, subnet ACL restrictions, missing routes, and other configuration failures.

Can a NACL block traffic even when the security group allows it?

Yes. A security-group allow does not bypass a network ACL. The packet must satisfy the applicable controls along its path. A NACL can explicitly deny a matching packet or fail to provide the required allow rule.

Can a security group override a NACL deny?

No. Security groups and NACLs are separate layers. A security-group rule cannot override a matching NACL deny rule.

Why does EC2 time out when port 443 is open in the security group?

Check whether the source in the TCP 443 rule matches the real client, then inspect the subnet NACL, especially its return path and ephemeral ports. Also confirm the route, public or private addressing path, operating-system firewall, and application listener.

Are AWS security groups stateful?

Yes. Return traffic for an allowed connection is permitted as part of that stateful flow. You do not need to create a mirror-image rule merely to permit the response to an already allowed request.

Are AWS network ACLs stateless?

Yes. NACLs do not remember that the first packet of a connection was permitted. The request and required response traffic must each match applicable allow rules.

Which NACL rule wins when two rules match?

The matching rule with the lowest rule number wins because AWS evaluates NACL rules from the lowest number upward and stops when it finds the first match.

Why is my NACL allow rule ignored?

Look for a lower-numbered rule that already matches the same traffic. A later allow rule cannot override an earlier matching deny.

What ephemeral ports should I allow in an AWS NACL?

Use the range required by the system that initiates the connection. Many Linux kernels use 32768-61000, modern Windows uses 49152-65535, while Elastic Load Balancing, NAT Gateway, and Lambda can use 1024-65535. Public-facing designs sometimes use the broader 1024-65535 range when they need to support varied clients.

Does the default AWS NACL allow traffic?

The default NACL contains numbered rules that allow IPv4 traffic in both directions, with corresponding IPv6 rules when applicable, followed by default asterisk deny rules for unmatched traffic.

Does a new custom NACL allow traffic automatically?

No. A newly created custom NACL begins without the permissive numbered rules of the default NACL. Add the inbound and outbound allow rules your subnet requires before relying on it for production traffic.

Can an AWS security group have deny rules?

No. Security groups contain allow rules. Traffic that is not permitted by an applicable rule is not admitted, but there is no explicit DENY rule that you insert ahead of another security-group rule.

Can an AWS NACL have deny rules?

Yes. NACL rules can explicitly allow or deny traffic. Because rule order matters, an early deny can intentionally block traffic before a broader later allow is evaluated.

Can VPC Flow Logs tell me whether traffic was rejected?

Yes. Flow Logs can record ACCEPT and REJECT actions for supported traffic. Use the flow direction, addresses, ports, and timing together with Reachability Analyzer when you need to narrow the rejection to a specific network control or path problem.

Can Reachability Analyzer identify a security group or NACL problem?

For supported paths, yes. It can return explanations such as ENI_SG_RULES_MISMATCH for security-group rule problems and SUBNET_ACL_RESTRICTION for subnet ACL restrictions. It can also expose missing routes and other non-firewall causes.

Should I use security groups or NACLs to protect a VPC workload?

Use security groups for fine-grained controls around resources and ENIs. Use NACLs when subnet-level allow or explicit deny behavior is useful as an additional layer. They solve different parts of the problem and can be used together rather than treated as interchangeable firewalls.

The final decision: which one is blocking you?

If the required source, protocol, or port is missing at the resource's security group, the security group is blocking you.

If a lower-numbered NACL deny matches first, the NACL is blocking you.

If the request is allowed but the return packet hits a missing ephemeral-port rule, the NACL is blocking you.

If Reachability Analyzer reports ENI_SG_RULES_MISMATCH, fix the applicable security-group rule.

If it reports SUBNET_ACL_RESTRICTION, fix the subnet ACL.

If it reports NO_ROUTE_TO_DESTINATION, neither firewall is the real problem.

If the network path is reachable and Flow Logs show ACCEPT, move to the operating system, listener, load balancer, TLS layer, or application.

Jake's booking page did not need a bigger firewall rule. It needed the right question. "Is TCP 443 allowed?" was too broad. "Can this client reach this ENI on TCP 443, and can the response return through the subnet to the client's ephemeral port?" is specific enough to solve.

If you are staring at a timeout right now, do not widen everything. Follow one packet forward, follow its response back, and stop at the first layer that cannot explain why the packet should pass. That is usually much faster than rebuilding rules until the error disappears.

📌 If you keep one line from this page

A security group remembers an allowed connection; a NACL does not, so trace the packet and its return path separately.

That one distinction explains most of the confusing "the port is open but it still times out" cases.

Revision note. Written October 3, 2026, with the Related resources tab in the console. Most VPC timeouts come down to one rule on one side of the path; trace the reply as carefully as the request, and it turns up.

Related