Skip to main content
Your first session is free. Claim mine
PacketMentor logo
Open menu
Home
Training
CCNA Library (74)
Browse all CCNA topics →
Network (13)
Device Operations (5)
Network Access (12)
Wireless (6)
IP Connectivity (10)
IP Services (11)
Security (10)
Automation (7)
CCNP Library (15)
LabsPricing
Contact 📞 +1 (860) 556-3010 Book a Call
← All topics
Security Fundamentals Foundational

Access Control Lists (ACLs)

Definitive CCNA-level ACL guide — first-match-wins, implicit deny, wildcard masks, standard vs extended vs named, direction (in vs out), the established keyword, time-based ACLs, named-ACL editing, 9 worked scenarios, and the ACL debug workflow.

TL;DR
  • Router reads ACL top-to-bottom. First match wins. After that, it stops processing. Every ACL ends with an invisible `deny ip any any` — the #1 'why isn't this working' cause.
  • Standard ACL filters source IP only — place close to destination. Extended ACL filters source + destination + protocol + port — place close to source.
  • Wildcard mask is the inverse of subnet mask (`255 − each octet`). `0.0.0.255` = /24, `0.0.0.0` = exact host, `any` = `0.0.0.0 255.255.255.255`.
  • Direction matters: `in` filters as packets arrive on an interface, `out` filters as they leave. Wrong direction is half of all ACL bugs.

Mental model

An ACL is a checklist a router runs over every packet on a configured interface. Each line is “if the packet looks like X, permit (or deny) it.” The router walks the list top to bottom, and the first matching line wins. After that, no further lines are checked.

The trap: if no line matches, there’s an invisible last line that drops the packet. This is the implicit deny. It’s the single biggest reason “my ACL isn’t working” tickets exist — engineers forget to allow traffic they didn’t think to call out.

The one rule: Every ACL ends with deny ip any any. You don’t type it. The router adds it.

If you write three permit lines and forget the fourth, anything that doesn’t match those three is dropped silently. Always test with the traffic you didn’t intend to block.

What ACLs are good for (and not good for)

ACLs are stateless packet filters. They look at one packet at a time — header fields only — and decide permit / deny. They don’t track connection state, don’t understand application protocols, and don’t inspect payload.

Good fits for ACLs

  • Coarse network-layer segmentation (block subnet A from subnet B)
  • Restricting management plane access (only NOC subnet may SSH the routers)
  • Filtering routing protocol updates (control which routes get advertised)
  • Marking traffic for QoS classification
  • Anti-spoofing (block source IPs that shouldn’t appear on this interface)
  • NAT match lists (defining which traffic to translate)
  • OSPF / EIGRP route-map match conditions

Bad fits for ACLs

  • Stateful inspection of TCP/UDP connections (use a firewall)
  • Layer-7 application awareness (use NGFW or app proxy)
  • Identity-aware policy (use 802.1X + ISE — see Cisco ISE Basics)
  • High-volume east-west DC traffic policy (use micro-segmentation)

An ACL is the right hammer when the nail is “I have IP X here and want to control whether it reaches IP Y on port Z.” For everything else, look at the firewall above the router.

Standard vs Extended vs Named — the three flavors

StandardExtendedNamed
Filters onSource IP onlySource + destination + protocol + port + moreEither type, with a name
Numbered range1–99 / 1300–1999100–199 / 2000–2699(uses name instead of number)
Apply whereClose to destinationClose to sourcePer-line editable
Default style in 2026Avoid — too coarseOKBest practice

For the CCNA exam: know all three. In production: always named, because you can edit individual lines.

Numbered standard ACL

R1(config)# access-list 10 permit 192.168.1.0 0.0.0.255
R1(config)# access-list 10 deny   any
R1(config)# interface Gi0/1
R1(config-if)# ip access-group 10 out

The router auto-adds the deny at the end, so the explicit deny any is technically redundant — but useful for clarity (and the explicit deny lets you add log to it).

Numbered extended ACL

R1(config)# access-list 100 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 80
R1(config)# access-list 100 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 443
R1(config)# access-list 100 deny   ip  any any log
R1(config)# interface Gi0/0
R1(config-if)# ip access-group 100 in
R1(config)# ip access-list extended WEB-ONLY
R1(config-ext-nacl)# permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 80
R1(config-ext-nacl)# permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 443
R1(config-ext-nacl)# deny   ip  any any log
R1(config-ext-nacl)# exit
R1(config)# interface Gi0/0
R1(config-if)# ip access-group WEB-ONLY in

Editing a named ACL by line number

R1# show access-list WEB-ONLY
Extended IP access list WEB-ONLY
    10 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq www  (542 matches)
    20 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 443  (1023 matches)
    30 deny   ip  any any log                                (17 matches)

! Insert a new permit at line 15 (between 10 and 20)
R1(config)# ip access-list extended WEB-ONLY
R1(config-ext-nacl)# 15 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 22

! Remove a line
R1(config-ext-nacl)# no 15

! Renumber to clean sequence
R1(config)# ip access-list resequence WEB-ONLY 10 10

This is impossible on numbered ACLs — you’d have to delete the whole thing and re-enter. Use named.

Wildcard masks — the inverse trick

Wildcard masks are the bit-inverse of subnet masks. A 0 in the wildcard means “must match”; a 1 means “don’t care.”

Easiest conversion: subtract each subnet-mask octet from 255.

SubnetWildcardMatches
255.255.255.0 (/24)0.0.0.255one /24 network
255.255.255.128 (/25)0.0.0.127one /25
255.255.255.192 (/26)0.0.0.63one /26
255.255.255.224 (/27)0.0.0.31one /27
255.255.255.240 (/28)0.0.0.15one /28
255.255.255.248 (/29)0.0.0.7one /29
255.255.255.252 (/30)0.0.0.3one /30
255.255.255.255 (/32)0.0.0.0exactly one host
255.255.0.0 (/16)0.0.255.255one /16
255.0.0.0 (/8)0.255.255.255one /8
0.0.0.0 (/0)255.255.255.255everything

Special shortcuts

! Match exactly one host
permit ip host 192.168.1.5 any
! Equivalent to:
permit ip 192.168.1.5 0.0.0.0 any

! Match any source / any destination
permit ip any any
! Equivalent to:
permit ip 0.0.0.0 255.255.255.255 0.0.0.0 255.255.255.255

Wildcard masks that aren’t subnet inverses

Subnet masks are always contiguous (e.g., 11111111.11111111.11111111.00000000). Wildcard masks don’t have to be — you can use discontinuous wildcards like 0.0.0.252 (matches first 6 bits of fourth octet, ignores last 2 bits). Rare but tested on the exam.

Example: match all even IPs in 10.1.1.0/24:

permit ip 10.1.1.0 0.0.0.254 any   ! matches .0, .2, .4, .6, … (all evens)

You won’t write these in real life. CCNA exam loves them.

In vs Out — the direction trap

interface GigabitEthernet0/0
 ip access-group MY-ACL in    ← filter packets ARRIVING on this interface
 ip access-group MY-ACL out   ← filter packets LEAVING this interface

Half of all real-world ACL bugs are direction mistakes, not rule mistakes. If your rule looks right but traffic still fails, swap direction and re-test before changing the rule.

Rule of thumb

  • Extended ACLs → close to the source (drop early to save bandwidth on transit links).
  • Standard ACLs → close to the destination (since they only filter source IP, putting them at source would block too much).

Visualizing direction

Think of yourself standing at the interface, looking at packets. in is what the interface receives. out is what the interface sends.

A common mistake: put in on the router’s WAN interface and expect to filter LAN traffic. The LAN traffic arrives on the LAN interface — it’s leaving the router on the WAN interface, so to filter LAN traffic on the WAN side, you’d use out.

The established keyword — stateless return-traffic trick

ACLs are stateless, but you can fake state for TCP using the established keyword. It matches packets that have ACK or RST flags set — i.e., packets that look like responses to an outbound connection, not new connections.

! Allow outbound TCP, allow only return traffic inbound
R1(config)# ip access-list extended OUTBOUND
R1(config-ext-nacl)# permit tcp 192.168.1.0 0.0.0.255 any
R1(config-ext-nacl)# deny ip any any
R1(config)# interface Gi0/1
R1(config-if)# ip access-group OUTBOUND in

R1(config)# ip access-list extended INBOUND
R1(config-ext-nacl)# permit tcp any 192.168.1.0 0.0.0.255 established
R1(config-ext-nacl)# deny ip any any
R1(config)# interface Gi0/0
R1(config-if)# ip access-group INBOUND in

This is the cheapest possible stateless firewall. It works for TCP only (UDP has no equivalent flag). A real firewall does this and much more — see Zone-Based Policy Firewall or any NGFW. But for CCNA-level understanding, established is the “implement basic state with ACLs” pattern.

Time-based ACLs

You can gate ACL entries by time of day or day of week:

R1(config)# time-range BUSINESS-HOURS
R1(config-time-range)# periodic weekdays 8:00 to 18:00

R1(config)# ip access-list extended LIMIT-STREAMING
R1(config-ext-nacl)# deny tcp 10.0.0.0 0.0.0.255 any eq 1935 time-range BUSINESS-HOURS
R1(config-ext-nacl)# permit ip any any

The deny only triggers during business hours. Outside that window, the line is ignored and the next line matches. Used for compliance, content filtering, or burstable bandwidth controls.

ACL match counters

Every ACL line has a hit counter:

R1# show access-list WEB-ONLY
Extended IP access list WEB-ONLY
    10 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq www  (1,247 matches)
    20 permit tcp 10.0.0.0 0.0.0.255 host 10.2.2.10 eq 443  (5,892 matches)
    30 deny   ip  any any log                                (84 matches)

The counters are your debugging gold:

  • All zero = ACL isn’t being hit (wrong interface? wrong direction? wrong source/dest?).
  • Hit count on the deny line = traffic you’re blocking. Use log keyword for syslog details.
  • Hit count growing on a permit you didn’t expect = something is matching that shouldn’t.

Reset counters:

R1# clear access-list counters WEB-ONLY

The log and log-input keywords

Append log to any ACL line and matches generate syslog entries:

deny ip any any log

log-input is stronger — also includes the source MAC + ingress interface, useful for tracking down rogue hosts:

deny ip 192.0.2.0 0.0.0.255 any log-input

Caveat: logging is CPU-intensive. Use sparingly — adding log to every line on a high-traffic ACL is a great way to brown out the router’s CPU. Use it on specific deny lines you actively monitor.

Reflexive ACLs — basic statefulness

reflexive ACLs were Cisco’s pre-firewall attempt at stateful filtering. Largely obsolete now (replaced by Zone-Based Firewall + dedicated firewalls) but show up on the CCNA blueprint.

ip access-list extended OUTBOUND
 permit tcp 192.168.1.0 0.0.0.255 any reflect TCP-OUT

ip access-list extended INBOUND
 evaluate TCP-OUT
 deny ip any any

The reflect TCP-OUT creates dynamic entries based on outbound traffic; evaluate TCP-OUT references them. The inbound side accepts return traffic without explicit permits per session.

For CCNA: recognize the syntax; you’ll basically never deploy it new in 2026.

Verification — the four commands

R1# show access-lists
R1# show access-list WEB-ONLY
R1# show running-config | include access-list
R1# show ip interface Gi0/0 | include access list
CommandTells you
show access-listsAll ACLs + their entries + match counters
show access-list <name>One ACL in detail
show ip interface <int>What ACLs are applied to that interface, in which direction
show running-config | include access-listAll ACL config lines in flat form

The combo of show access-lists (counters) + show ip interface (where applied + direction) covers most debug needs.

The ACL debug workflow

When an ACL “isn’t working”:

  1. Is it applied to the right interface? show ip interface <int>. Check both Outgoing access list and Inbound access list lines.
  2. Is it the right direction? Swap inout and re-test if uncertain.
  3. Are hit counters incrementing? show access-list <name>. If counters are zero, the ACL is being bypassed — either applied wrong, or traffic isn’t on this interface.
  4. Which line is matching? Look at counters. Sometimes a too-general permit higher in the list catches traffic you thought would hit a later, more specific line.
  5. Is the implicit deny biting you? Run show access-list and check the bottom line’s hit count. If high, you’re dropping traffic you forgot to allow.
  6. Wildcard mask correct? Common to type subnet mask by accident. Verify by sanity-checking the binary.
  7. Did log reveal anything in syslog? Add log to a suspect line, generate traffic, check show logging.

Worked scenarios


Scenario 1. You want to block subnet 192.168.50.0/24 from reaching 10.0.0.0/8. Where do you place the ACL?

Answer: Extended ACL (because you’re matching destination too) close to the source — on the router interface where 192.168.50.0/24 enters. Apply in. Drops traffic before it traverses any backbone link.


Scenario 2. You write an ACL with three permit lines and apply it. All other traffic is dropped. Why?

Answer: Implicit deny at the end. The router silently adds deny ip any any after your three permits. Fix: add an explicit permit ip any any at the end if you wanted only those three blocked and everything else allowed (you should rewrite the ACL with explicit denies + a final allow).


Scenario 3. ACL line: permit tcp 10.1.1.0 0.0.0.255 any eq 80. Will this match a TCP reply from a web server to 10.1.1.5?

Answer: No. The line specifies source 10.1.1.0/24 and destination port 80. Web server reply has source port 80 and destination 10.1.1.5 — that’s the opposite direction. You’d need either:

  • A second line permit tcp any eq 80 10.1.1.0 0.0.0.255 on the return-direction interface, or
  • The established keyword on the return-direction inbound ACL.

Scenario 4. Your ACL has these two lines, in this order:

permit tcp any host 10.2.2.10 eq 80
deny   tcp 192.168.1.5 0.0.0.0 host 10.2.2.10 eq 80

Will 192.168.1.5 be able to reach the web server?

Answer: Yes. First match wins. The permit tcp any matches 192.168.1.5 first; the explicit deny never gets evaluated. Fix: reorder — put the specific deny above the general permit.


Scenario 5. You apply access-list 10 deny 10.1.1.0 0.0.0.255 to an interface as ip access-group 10 in. No permits below it. What gets through?

Answer: Nothing. The deny blocks 10.1.1.0/24, then the implicit deny ip any any blocks everything else. Always end a standard ACL with permit any if you want non-denied traffic through.


Scenario 6. You want to deny SSH (port 22) to your router from everywhere except management VLAN 192.168.99.0/24. How?

Answer: Apply an ACL to the VTY lines, not an interface:

ip access-list standard MGMT-ONLY
 permit 192.168.99.0 0.0.0.255
 deny any log
!
line vty 0 4
 access-class MGMT-ONLY in
 transport input ssh

access-class on line vty is the management-plane ACL. Different from ip access-group (data-plane).


Scenario 7. ACL says:

permit tcp 10.0.0.0 0.0.0.255 any eq 80

A host at 10.0.0.5 tries to reach a web server on port 8080. Allowed?

Answer: No. eq 80 matches destination port 80 exactly. Port 8080 doesn’t match. The packet falls through to the implicit deny.


Scenario 8. You want to allow ICMP echo (ping) from a /27 subnet to a specific server, and block all other traffic from that subnet. Write the ACL.

Answer:

ip access-list extended PING-ONLY
 permit icmp 10.1.1.0 0.0.0.31 host 10.2.2.10 echo
 deny ip any any log

Apply in on the source-side interface. Note 0.0.0.31 = /27 wildcard.


Scenario 9. You have a wildcard mask of 0.0.0.252. What does it match?

Answer: First 30 bits exact, last 2 bits “don’t care.” If applied to a host 10.1.1.0 it matches 10.1.1.0 and 10.1.1.1 and 10.1.1.2 and 10.1.1.3 (last 2 bits varying). Discontinuous wildcards are tested on CCNA — recognize them, don’t deploy them.

Common mistakes

  1. Forgetting the implicit deny. Three permits don’t help if you also forgot to allow something. Always test what you didn’t intend to block.

  2. Wrong direction (in vs out). Number-one cause of “ACL isn’t working.” If unsure, swap and re-test.

  3. Wildcard mask backwards. Typing 255.255.255.0 where you needed 0.0.0.255. Easy mistake; common exam trap.

  4. Too-general line above a too-specific one. First match wins. Put host 10.1.1.5 rules above subnet rules above any rules.

  5. Applying to the wrong interface. Extended ACL belongs close to source. Standard close to destination. Mixed up = wasted bandwidth or unintended blocks.

  6. Blocking return traffic. Permitting outbound TCP but blocking inbound breaks every reply. Use established keyword or move to stateful filtering.

  7. Editing a numbered ACL line-by-line. Impossible. Remove and re-enter, or use a named ACL.

  8. Forgetting access-class for VTY. Using ip access-group on the management interface doesn’t protect the VTY lines. Always pair: data-plane filter on interface, management-plane filter on VTY.

  9. Logging too aggressively. Adding log to every line on a high-traffic ACL spikes CPU. Use sparingly, on specific deny lines.

  10. Resequencing without checking dependencies. ip access-list resequence re-numbers lines — useful for tidying — but verify automation tools and runbooks don’t reference specific line numbers.

  11. Mixing IPv4 and IPv6 ACLs. They’re separate. ip access-list is IPv4; ipv6 access-list is IPv6. Both must be applied separately to interfaces.

  12. Using a standard ACL where you needed extended. “Block 10.1.1.5 from reaching 10.2.2.10” is impossible with standard (which only filters source). You need extended.

Lab to try tonight

  1. Topology — two LANs and one router between them. LAN-A = 10.1.1.0/24. LAN-B has a web server at 10.2.2.10 and an FTP server at 10.2.2.20.

  2. Web-only goal — from LAN-A, allow only HTTP (port 80) to the web server. Block everything else. Write an extended named ACL, apply in on the LAN-A interface, test:

    • curl http://10.2.2.10 should succeed
    • ping 10.2.2.10 should fail
    • curl ftp://10.2.2.20 should fail
    • show access-list — verify hit counters
  3. Add ICMP for diagnostics — add permit icmp 10.1.1.0 0.0.0.255 host 10.2.2.10 echo above the deny. Ping now works. Trace flow with counters.

  4. Direction swap drill — move the same ACL to out on the LAN-B interface. Observe the same end result, but show access-list hit counters move differently (and reverse-direction traffic hits different lines).

  5. VTY restriction — set up line vty 0 4 with access-class MGMT-ONLY in allowing only one mgmt subnet. Try SSH from an unauthorized subnet — should be denied. From the mgmt subnet — should succeed.

  6. established trick — implement a “stateless firewall” using only ACLs. Outbound TCP from LAN-A permitted. Inbound on WAN only allowed if established. Verify a browser session works but unsolicited inbound (e.g., remote SSH attempt to a LAN-A host) is dropped.

  7. Wildcard practice — use 0.0.0.7 (/29) wildcard to permit only 10.1.1.010.1.1.7. Verify hosts .5 and .6 are allowed; .10 is denied.

  8. Resequence — after several inserts, run ip access-list resequence WEB-ONLY 10 10 to clean up line numbering. Verify with show access-list.

  9. Bonus: time-based — define a BUSINESS-HOURS time-range and apply to one of your rules. Verify behavior changes at the boundary.

Cheat strip

ConceptPlain English
First match winsRouter reads top to bottom, stops on first match
Implicit denyInvisible deny ip any any at the end of every ACL
Wildcard maskInverse of subnet mask. 0 = must match, 1 = don’t care
Standard ACLSource IP only. 1–99 / 1300–1999. Close to destination.
Extended ACLSource + dest + protocol + port + more. 100–199 / 2000–2699. Close to source.
Named ACLEditable per line. Always prefer over numbered in production.
in vs outDirection the ACL filters relative to the interface
host XShortcut for X 0.0.0.0 (one specific IP)
anyShortcut for 0.0.0.0 255.255.255.255 (anywhere)
eq <port>Destination/source port equals X. Other operators: gt, lt, range
establishedMatch TCP packets with ACK/RST set (cheap stateless filter)
log / log-inputSyslog the match. Use sparingly — CPU heavy
access-class (VTY)Apply ACL to management plane, not data plane
Resequenceip access-list resequence NAME 10 10 cleans up line numbers
IPv4 ≠ IPv6Separate ACL types, must be applied separately
Time-rangeGate lines by time of day / day of week
Match countersshow access-list — your debug gold
Direction trapHalf of all ACL bugs. If rule looks right, swap direction before changing rule.

Looking for the longer one-page reference? See the ACL Cheat Sheet.

Master this on a real network

Want this drilled into reflex?

1:1 weekly sessions, live feedback on your labs, and US interview prep — built around the CCNA® exam blueprint. Free first session. No card on file until you decide.

Claim my free session →

One topic per email, every fortnight

VLANs, OSPF, ACLs, subnetting, automation — written like this. Unsubscribe in one click.

We respect your inbox. One email per week, max. Unsubscribe any time.

Start typing — or browse popular topics below.

↑↓ navigate open Searches topics · labs · programs · pages