A Fail2ban false positive locks out someone who did nothing wrong: a developer retyping a password, a monitoring probe, or a mail client reconnecting too fast. This guide walks through identifying which jail fired, confirming the ban was wrong, and tuning the jail so the same address is not banned again.
The fix is almost never "turn Fail2ban off". It is a small change to maxretry, findtime, bantime or ignoreip in jail.local, or a correction to the filter regex that matched the wrong log line.
Before you start
You need:
- Root or sudo access to the Linux VPS, and the ability to edit files under
/etc/fail2ban/. - The IP address that was banned, for example
203.0.113.10. - Fail2ban already installed and running. If it is not, start with installing Fail2ban to protect SSH.
- A rough idea of when the ban happened, so you can match it against log timestamps.
Warning: Restarting or reloading Fail2ban clears the current ban list. Any address banned right now will be unbanned. That is usually fine, but do not reload during an active brute-force attack without checking the logs first.
Find which jail banned the address
List the jails and their current state:
sudo fail2ban-client statusThen inspect the jail you suspect, usually sshd:
sudo fail2ban-client status sshdThe output shows the filter file, the log path, and the banned IP list:
Status for the jail: sshd
|- Filter
| |- Currently failed: 1
| |- Total failed: 47
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 1
|- Total banned: 3
`- Banned IP list: 203.0.113.10If you do not know which jail is responsible, check them all:
for j in $(sudo fail2ban-client status | grep "Jail list" | cut -d: -f2 | tr -d ' ' | tr ',' ' '); do
echo "== $j =="
sudo fail2ban-client status "$j" | grep "Banned IP list"
doneConfirm it is a Fail2ban false positive
Before changing anything, look at the log lines that triggered the ban. For SSH on Debian or Ubuntu:
sudo journalctl -u ssh --since "2 hours ago" | grep 203.0.113.10On AlmaLinux or Rocky, SSH logs to /var/log/secure:
sudo grep 203.0.113.10 /var/log/secureFor Nginx, check the access log:
sudo grep 203.0.113.10 /var/log/nginx/access.log | tail -20Read the matched lines and ask one question: did this client actually fail authentication, or did the filter match something harmless? A real user typing a wrong password three times is a tuning problem. A 404 request being counted as an auth failure is a filter problem.
You can also replay the log against the filter to see exactly what matches:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.confTune maxretry, findtime and bantime
These three settings control how strict a jail is:
maxretry— how many failures are allowed inside the window.findtime— the length of that window in seconds.bantime— how long the ban lasts.
Never edit /etc/fail2ban/jail.conf. It is overwritten on package upgrades. Put overrides in /etc/fail2ban/jail.local:
[DEFAULT]
# Allow more mistakes before banning
maxretry = 5
findtime = 10m
bantime = 1h
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1hThe full set of options is covered in configuring bantime, findtime and maxretry in jail.local.
Test the configuration before applying it:
sudo fail2ban-client -tIf it reports OK, reload:
sudo fail2ban-client reloadVerify the values took effect:
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd bantimeWhitelist trusted addresses with ignoreip
For known-good sources — your office IP, a monitoring server, a CI runner — whitelisting is cleaner than loosening the jail for everyone. Add them under [DEFAULT] in jail.local:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10 198.51.100.0/24ignoreip accepts single addresses and CIDR ranges, separated by spaces. Reload and confirm:
sudo fail2ban-client reload
sudo fail2ban-client get sshd ignoreipTip: Do not whitelist a whole ISP range just to unblock one user. Whitelisting a /16 can exclude thousands of addresses from every jail on the server.
To lift a ban immediately without touching config, use fail2ban-client set sshd unbanip 203.0.113.10. The full procedure is in checking banned IPs and unbanning an address.
Fix the filter instead of loosening the jail
If the log lines were never authentication failures, the filter regex is wrong and tuning will only hide the problem. A common case is a web jail matching a 404 or a health-check probe.
Test a candidate regex against real logs before deploying it:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-badbots.confLook at the "Lines matched" count. If it matches normal traffic, tighten the pattern. Put custom filters in /etc/fail2ban/filter.d/ and reference them from a jail in jail.local. The workflow is described in writing a custom filter and testing it with fail2ban-regex and in creating filters for specific application log errors.
Warning: A filter with a very broad regex can ban your own users in bulk. Always run fail2ban-regex against a day of production logs and check the match count before enabling the jail.
Check it works
- Ask the affected user to connect again and confirm they are not blocked.
- Watch the jail while they do it:
sudo fail2ban-client status sshd- Confirm the failed count rises without a ban, which proves
maxretryis now high enough:
|- Currently failed: 2
|- Total failed: 49
`- Banned IP list:- Check the Fail2ban log for filter errors after the reload:
sudo tail -50 /var/log/fail2ban.log- Run a deliberate wrong-password attempt from a test address you control and confirm the ban still triggers. A jail that never bans is not protection.
Troubleshooting
- The same user is banned again within minutes.
findtimeis too long relative to their retry pattern, ormaxretryis still too low. Raisemaxretryto 5–6 and shortenfindtimeto10m. fail2ban-client -tfails after editing jail.local. A duplicate section header or a missing=is the usual cause. Check the reported line number and confirm each jail appears only once.- Changes do not apply. You edited
jail.confinstead ofjail.local, or forgot to reload. Runsudo fail2ban-client reloadand re-check withfail2ban-client get. ignoreiphas no effect. The address is still banned from a previous run. Unban it manually, then confirm withfail2ban-client get <jail> ignoreipthat the value parsed correctly.- A jail bans nobody after tuning. The filter regex no longer matches the log format, often after an OS or application upgrade. Re-run
fail2ban-regexand compare against the current log lines. - Bans disappear after a reboot. The ban database was not persisted. Check the
dbfilesetting injail.localand confirm the path is writable.
Next steps
- Protect Nginx with Fail2ban: bad bots, scanners and auth to apply the same tuning to web jails.
- Get email or Telegram alerts when Fail2ban bans an IP so you notice false positives early.
- Fail2ban not banning? Common causes and fixes for the opposite problem.
- Use Fail2ban with firewalld or nftables ban actions if you changed the firewall backend.
