Mental model
A switch port, by default, accepts traffic from any device that plugs in. That’s flexible, but it means anyone who can physically reach a network port (visitor jack in a meeting room, a janitor’s closet, a coffee shop) can plug in a laptop and join your LAN.
Port security says: “this port is locked to one specific MAC address (or N specific MAC addresses) — anything else, react.”
That’s the whole concept. The rest is detail: how the MAC gets registered, and what “react” means when an unauthorized device shows up.
Three ways the switch learns the allowed MAC
| Mode | How it learns | Survives reload? |
|---|---|---|
| Static | Hardcoded with switchport port-security mac-address X | Yes |
| Dynamic | Learned from the first frame on the port | No — lost on reload |
| Sticky | Learned dynamically, then saved to running-config | Yes (once write memory runs) |
Sticky is the typical production choice. Set it up, let the legitimate device connect once (its MAC gets learned and saved), and you’re protected forever.
Three ways the switch reacts to a violation
| Violation mode | What happens | Counter increments? | Log message? |
|---|---|---|---|
| shutdown (default) | Port goes to err-disable (down) | Yes | Yes |
| restrict | Frames from bad MACs dropped, port stays up | Yes | Yes |
| protect | Frames dropped silently | No | No |
Most production deployments use restrict — it logs the event without killing the port (which would also kick off the legitimate user if someone else briefly plugs in).
Commands
Basic sticky port security (the production default)
SW1(config)# interface GigabitEthernet0/1
SW1(config-if)# switchport mode access
SW1(config-if)# switchport access vlan 10
SW1(config-if)# switchport port-security
SW1(config-if)# switchport port-security maximum 1
SW1(config-if)# switchport port-security mac-address sticky
SW1(config-if)# switchport port-security violation restrict
Read it as: “this access port allows up to 1 MAC address; learn it dynamically and save it; on violation, drop frames but stay up.”
Allow a phone + a PC behind the phone
A common scenario: a Cisco IP phone plugs into the wall, and a PC plugs into the phone. Two MACs on one port.
SW1(config-if)# switchport port-security maximum 2
Statically allow a specific MAC
SW1(config-if)# switchport port-security mac-address aaaa.bbbb.cccc
Verification
SW1# show port-security
SW1# show port-security interface GigabitEthernet0/1
SW1# show port-security address
SW1# show interfaces status err-disabled
show port-security is the do-everything command. It shows: which ports have port-security enabled, max MACs allowed, current MACs learned, violation count, action mode.
Recovering from err-disable
When a port hits a violation in shutdown mode, it’s err-disable — down, won’t come up by itself.
Manual recovery
SW1(config)# interface GigabitEthernet0/1
SW1(config-if)# shutdown
SW1(config-if)# no shutdown
Auto-recovery after a timeout
SW1(config)# errdisable recovery cause psecure-violation
SW1(config)# errdisable recovery interval 300
Tells the switch: auto-recover from port-security err-disables after 300 seconds. Use cautiously — if the violation persists, the port will flap every 5 minutes.
Common mistakes
-
Enabling port-security on a trunk port. Port-security is for access ports only — it doesn’t understand the tagging on trunks. The switch will refuse the command on a trunk. Set the port to access first.
-
Leaving
maximumat default 1 when a phone is in line. A Cisco IP phone has its own MAC, and the PC behind it has another. With max 1, the phone learns first, the PC violates. Set max to 2 (or use voice VLAN handling that exempts the voice VLAN). -
Using dynamic learning in production. Learned MACs are lost on reload. Power cycles → no one can use the port → tickets. Always use sticky in production.
-
Setting violation mode to shutdown without err-disable recovery. Someone briefly plugs in the wrong device → port is dead until an admin SSHes in. For low-stakes deployments, use restrict + log.
-
Forgetting to save running-config after sticky learning. The MAC appears in
show running-config, but if you don’twrite memory, a reload wipes it. Always save after enabling sticky. -
Locking a port to a MAC, then swapping the connected device. New device → new MAC → violation. To swap devices legitimately, either:
no switchport port-security mac-address sticky(clears learned), then re-enable; or update the static MAC.
Lab to try tonight
- One switch. Plug a laptop into Gi0/1.
- Configure Gi0/1 for sticky port security with max 1, violation restrict.
- Verify with
show port-security— should show one MAC learned (your laptop’s). - Unplug your laptop, plug in a different device. Verify with
show port-security: violation counter increments, port stays up but frames are dropped. - Plug your laptop back in. Should work immediately.
- Switch violation to
shutdown. Repeat the swap — port should now err-disable. - Add
errdisable recovery cause psecure-violation+errdisable recovery interval 60. Watch the port recover automatically after 60s.
Cheat strip
| Concept | Plain English |
|---|---|
| Static / Dynamic / Sticky | How the allowed MAC is configured. Use sticky in production. |
| Maximum N | How many MACs are allowed on the port |
| Violation: shutdown | Default. Port err-disables on violation. |
| Violation: restrict | Drop frames + log, port stays up |
| Violation: protect | Drop frames silently, no log |
| Sticky | Dynamic + save-to-running-config. Most common production setting. |
| err-disable | The state a port enters after a shutdown-mode violation |
| Recovery | Manual shut/no shut or auto via errdisable recovery |