OPNsenseXI · Firewall StatesFirewall state operations
Clearing states — pfctl -k vs pfctl -F state, and when each is right
What you'll learn
- Use pfctl -k to kill specific state entries by source, destination, or label
- Use pfctl -F state to flush the entire state table when appropriate
- Recognise the service-affecting implications of bulk state clearing
- Apply the operational discipline that picks targeted vs bulk clearing
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
The state table is the firewall’s working memory. Sometimes that memory needs to be cleared. A state entry for a connection that no longer exists (the application crashed and the client never sent a FIN). A state entry that is causing a problem (a stuck connection that should be terminated). A state entry whose associated rule has changed and the operator wants the new rule to apply.
PF provides two clearing commands: pfctl -k for targeted removal of specific entries, and pfctl -F state for bulk flush of the entire table. The two commands are not interchangeable; the wrong choice is service-affecting.
This lesson covers when each is appropriate and the operational discipline that picks the right tool.
The targeted kill: pfctl -k
pfctl -k removes specific state entries based on filter criteria. The syntax:
pfctl -k <source-or-destination>
pfctl -k <source> -k <destination>
pfctl -k label <rule_label>
The simplest form kills every state involving a specific IP:
pfctl -k 192.0.2.50
This kills all states where 192.0.2.50 is either source or destination. Useful when a host’s connections need to be terminated.
The two-criterion form kills only states matching both:
pfctl -k 192.0.2.50 -k 203.0.113.50
The label form kills states that match a specific rule label:
pfctl -k label -k 'id <rule_id>'
This requires the rule to have a label in the GUI.
$ pfctl -k 192.0.2.50 && echo OK1 states killed
OKIllustrative output
The bulk flush: pfctl -F state
pfctl -F state removes every entry in the state table. The firewall starts with an empty state table; all subsequent packets are evaluated against the rules.
pfctl -F state
There is no filter, no confirmation prompt, no rollback. Every active TCP session that traverses the firewall is terminated. Every VPN tunnel, every SSH session, every long-poll HTTP request — all gone.
This is a service-affecting command. In a production environment, it should be run only during a maintenance window with advance notice.
$ pfctl -F state && echo 'all state cleared'43 states cleared
all state clearedIllustrative output
When each is appropriate
Targeted kill: pfctl -k
Use pfctl -k when:
- A specific host’s connections need to be terminated. An IP reassignment, a misbehaving host, a security incident. Use
pfctl -k <host_ip>. - A specific flow needs to be terminated. A stuck TCP session. Use
pfctl -k <src> -k <dst>. - A rule change needs to apply to existing flows. After editing a firewall rule, existing states continue to match the old rule. Clear the relevant states with
pfctl -k <src>for the affected flows. - A specific rule’s states need to be cleared. If the rule has a label, use
pfctl -k label -k <label>.
Bulk flush: pfctl -F state
Use pfctl -F state when:
- A maintenance window is in effect. The operator has notified users, and a complete reset is part of the planned work.
- A config apply that drops all state is unavoidable. Some operations (firmware upgrade, major config change) require a full state reset.
- The state table is corrupted or exhausted. A pathological state requires a flush to recover.
In all other cases, pfctl -k is the right tool.
Clearing states after a rule change
The most common operational reason to clear states is a rule change. PF caches the rule decision in the state entry; an existing flow continues to match the state, not the new rule. To apply the new rule to the flow, clear the state.
The pattern:
- Apply the new rule via the GUI. OPNsense applies the change.
- Identify the affected flows. Use
pfctl -s state | grep <criteria>to find the flows that match the old rule. - Kill the affected states with
pfctl -k. For specific IPs, flows, or rule labels. - Verify. The next packet of the affected flow is evaluated against the new rule.
The discipline: do not blanket-flush the entire state table to apply a rule change.
Killing states by rule label
If the rule has a label (set in the GUI under Advanced Options → Label), pfctl -k can target all states created by that rule.
For example, a rule that permits outbound HTTPS from the LAN could have the label lan_https_out. After a change to that rule, the operator can clear all states with:
pfctl -k label -k lan_https_out
$ pfctl -k label -k lan_https_out127 states killedIllustrative output
The discipline: assign labels to rules that will need targeted state clearing. Without a label, the operator must identify the affected states by IP, which is fragile.
Operational discipline
The discipline for state clearing has three parts:
Document before clearing
Before running pfctl -k or pfctl -F state, document:
- What you are about to do.
- Why.
- The expected impact.
- The time of the action.
This is the change record. It is what the next operator reads when the action’s effects are being investigated.
Verify with a test packet
After clearing, verify the firewall is doing what you expected. Send a test packet from a host that matches the cleared flow; confirm the firewall’s behaviour matches the new rule.
Have a rollback
For non-emergency state clearing, have a rollback plan. If the new rule or the state clearing causes an incident, what is the recovery path?
Common mistakes
Three patterns cause incidents:
- Bulk flush to apply a rule change. The operator did not realise they could clear specific states; they flushed everything. The fix is to use
pfctl -kwith the affected IP, destination, or label. - Targeted kill of the wrong IP. The operator mistyped an IP or a label and killed the wrong states. The fix is to verify the target with
pfctl -s statebefore killing. - State clearing without a change record. The operator cleared states as part of a maintenance task; the next operator sees the cleared table and has no idea why. The fix is to document the action before executing.
Summary
pfctl -k <ip>kills states involving a specific IP;pfctl -k <src> -k <dst>kills specific flows;pfctl -k label -k <label>kills states by rule label.pfctl -F stateflushes the entire state table. Service-affecting.- Use targeted kill for routine changes (rule edits, IP reassignments, misbehaving hosts). Reserve bulk flush for maintenance windows.
- After a rule change, clear the affected states with
pfctl -kto apply the new rule to existing flows. - Assign labels to rules that will need targeted state clearing.
- Document before clearing; verify after; have a rollback.
Knowledge check · 4 questions
Q1. You change a firewall rule that permits outbound HTTPS from the LAN. Existing HTTPS sessions from the LAN continue to use the old rule behaviour. What is the most appropriate action?
Q2. pfctl -F state is appropriate to run during normal production hours when a rule change needs to apply to existing flows.
Q3. Which of the following are valid uses of pfctl -k? Select all that apply.
Q4. You run pfctl -k label -k lan_https_out and see "0 states killed". The rule has the label lan_https_out and was active. What is the most likely explanation?
Passing score: 75%. Answers are checked in this browser.