sshd "srclimit_penalise: activating penalty": What the Penalty Means
Published
sshd has accumulated enough penalty against one client address range to start refusing its connections, and the line names the address, the number of seconds left on the block and what the client did to earn it.
What it looks like
Oct 18 03:51:11 web1 sshd[918]: srclimit_penalise: 203.0.113.7/32: activating ipv4 penalty of 20 seconds for penalty: failed authentication
- 1Time — When it was logged; this format has no year or time zone
- 2Host — The server’s host name
- 3Program — sshd and its process ID
- 4Source address — The client’s IP address
- 5Penalty length — How long this penalty lasts
- 6Penalty reason — What the address did to earn it
Example lines as /var/log/auth.log shows them (/var/log/secure on RHEL and Fedora):
Oct 18 03:51:11 web1 sshd[918]: srclimit_penalise: 203.0.113.7/32: activating ipv4 penalty of 20 seconds for penalty: failed authentication Oct 18 04:02:35 web1 sshd[918]: srclimit_penalise: 198.51.100.22/32: activating ipv4 penalty of 16 seconds for penalty: connections without attempting authentication Oct 18 04:19:07 web1 sshd[918]: srclimit_penalise: 2001:db8::42/128: activating ipv6 penalty of 20 seconds for penalty: exceeded LoginGraceTime
On our own server, the 30 days to 25 October 2026
…: activating … penalty of … seconds for …
403
lines · about 13 a day · 61 source addresses
Last seen 22 October 2026
LogTriage's production API server (Hetzner, Germany): port 22 open to the internet, key-only since 6 October 2026 (password and keyboard-interactive authentication off); nginx in front of the API on ports 80 and 443. Counted weekly from the sshd journal; no address ever leaves the server. More in the monthly attack report; which free blocklists already list these attackers is measured in the IP blocklist report, and you can check the addresses in your own log.
Where the line comes from
Format strings as written in the source of OpenSSH 10.2p1 — the versions this server runs. Each links to the exact line.
-
%s: activating %s penalty of %lld seconds for %smessage · srclimit.c:451 (OpenSSH) -
srclimit_penalise(struct xaddr *addr, int penalty_type)function name, logged as the prefix · srclimit.c:346 (OpenSSH) -
penalty: failed authenticationreason · srclimit.c:378 (OpenSSH) -
penalty: connections without attempting authenticationreason · srclimit.c:382 (OpenSSH) -
penalty: exceeded LoginGraceTimereason · srclimit.c:390 (OpenSSH)
What it means
OpenSSH tracks, per source address, connections that ended in a way that may represent an attack, and adds seconds to that source’s penalty each time. This line is written at the transition: the accrued penalty has passed the minimum threshold, the entry was not already active, and sshd is now refusing connections from that address range. The manual puts it plainly: “If a penalty is enforced against a client then its source address and any others in the same network, as defined by PerSourceNetBlockSize, will be refused connection for a period.” It also notes that “A penalty doesn’t affect concurrent connections in progress”.
Read the four fields in order:
- The address with its mask — the source address after
PerSourceNetBlockSizehas been applied. The default is32:128, “which means each address is considered individually”, so you normally see a single host as/32or/128. ipv4oripv6— which penalty table the entry lives in. The manual notes IPv4 and IPv6 addresses are tracked separately.- The seconds — the penalty remaining when it was activated. Because penalties accumulate, this is a running total, capped by
max(default 10m), not the cost of one bad connection. - The reason — the string that tells you what the client did.
The srclimit_penalise: prefix is the function name; the penalty table lives in the listening sshd process, which is why these lines carry the listener’s PID rather than a per-connection sshd-session PID.
Is it an attack?
The reason string maps one-to-one onto a PerSourcePenalties keyword and its documented default duration:
| Reason in the line | Keyword (default) | Reading |
|---|---|---|
penalty: failed authentication | authfail (5s) | Clients “that disconnect after making one or more unsuccessful authentication attempts” — password or key guessing. Pair with Failed password and Invalid user lines |
penalty: connections without attempting authentication | noauth (1s) | Banner grabs and port surveys; the manual warns this “may penalise legitimate scanning tools such as ssh-keyscan(1)“ |
penalty: exceeded LoginGraceTime | grace-exceeded (10s) | Connections that sat open past LoginGraceTime — see Timeout before authentication |
penalty: connection prohibited by RefuseConnection | refuseconnection (10s) | The administrative refusal you configured, firing as intended |
penalty: caused crash | crash (90s) | A client that crashed sshd — rare, and the one reason here worth an immediate, full investigation |
On an internet-facing host the first two reasons are routine background noise and the line is a sign the control is working. What changes severity is the company the line keeps: many authfail penalties against named staff or service accounts, a penalty for a source inside your own estate, or any Accepted line from an address that was being penalised.
How to investigate
Pivot on the penalised address and on the reason counts.
# Last 24 hours (Debian/Ubuntu unit is ssh; on RHEL/Fedora use -u sshd)
sudo journalctl -u ssh --since "24 hours ago" | grep 'srclimit_penalise:'
# Most-penalised sources (/var/log/auth.log; on RHEL/Fedora /var/log/secure)
sudo grep -oP 'srclimit_penalise: \K\S+(?=: activating)' /var/log/auth.log \
| sort | uniq -c | sort -rn | head -20
# Why they were penalised
sudo grep -oP 'activating \S+ penalty of \d+ seconds for \K.+$' /var/log/auth.log \
| sort | uniq -c | sort -rn
# What one source actually did, in order
sudo grep '203\.0\.113\.7' /var/log/auth.log | tail -40
# Did anything from these sources get in?
sudo grep -E 'Accepted (publickey|password)' /var/log/auth.log | tail -50
# The penalty settings actually in effect
sudo sshd -T | grep -iE 'persourcepenalt|persourcenetblocksize|maxauthtries|logingracetime|passwordauthentication'
An exported auth.log can be grouped by source in the browser log analyzer, and the one-source-many-names pattern behind most authfail penalties is encoded in the SSH brute-force rule.
How to stop it
The line is the remedy, not the problem, so the work is making it rarer and making it count.
- Keep
PerSourcePenaltiesenabled. The manual states penalties are enabled by default and may be disabled with thenokeyword; individual durations are overridden by keyword arguments such as"crash:2m". - Exempt addresses you control with
PerSourcePenaltyExemptList— your bastion, scanners and monitoring — so a health check never locks itself out. The default is to exempt nothing. - Reduce exposure. Restricting port 22 at the firewall, or putting it behind a VPN or bastion, removes most penalised connections entirely.
- Take passwords out of play.
PasswordAuthentication no(defaultyes) and, where PAM is enabled,KbdInteractiveAuthentication no(defaultyes); the manual notes PAM keyboard-interactive authentication usually serves an equivalent role to password authentication. - Tighten the limits that feed penalties:
MaxAuthTries(default 6),LoginGraceTime(default 120 seconds),PermitRootLogin(defaultprohibit-password) andAllowUsers, which by default allows login for all users. - Watch the table size if you are facing a distributed botnet:
max-sources4/max-sources6default to 65536 each, and the defaultoverflowmode ispermissive, which “allows new connections by removing existing penalties early”.
sudo sshd -t && sudo systemctl reload ssh
Validate before reloading, and keep a working session open until a new one connects.
Lines you will see next to it
- … for … from … port … ssh2… sshd rejected a password authentication attempt — the line names the account that was tried, the client address and the client's source port, and marks names that are not usable accounts on this host with "invalid user".
- Invalid user … from … port … sshd rejected the login because the name the client asked for is not a valid account on this host, so no password or key was ever checked against a real user.
- Connection closed by … The client at the other end of the SSH connection went away — closed it cleanly, or reset it — and sshd logged the address, port and (if the client had already named an account) the user it was trying before it quit.
- Timeout before authentication for …, pid = … A connection was accepted but did not finish authenticating inside the login grace period, so sshd terminated the pre-authentication process and the listener logged the client and that process's pid.
- maximum authentication attempts exceeded for … from … port … ssh2 One SSH connection used up every authentication attempt sshd allows it — the MaxAuthTries limit, 6 by default — so sshd logged the account name, source address and port and tore the connection down.
Detect it
Frequently Asked Questions
- Does this line mean someone broke in?
- No. It is sshd defending itself, not an authentication result. The penalty table only records how a connection ended — failed authentication, no authentication attempt, grace time exceeded, a crash, or a connection refused by RefuseConnection — and this line is written when sshd starts refusing further connections from that address range. To find out whether anything succeeded, look for Accepted lines from the same source.
- Why does the line say 20 seconds when the authfail default is 5 seconds?
- Penalties accumulate. The manual says multiple penalties from the same source accumulate up to a maximum (default 10m) and that penalties are not applied until a minimum threshold time has been accrued (default 15s). The code only logs this line when the accrued time passes the minimum and the entry is not already active, so the number you see is the remaining penalty at that moment, not the per-event duration.
- Could a penalty block my own users or monitoring?
- Yes, if they share the penalised address range. Penalties apply to the source address and any others in the same network as defined by PerSourceNetBlockSize, whose default is 32:128 — each address considered individually — so a NAT gateway or a health check that connects without authenticating can earn one. PerSourcePenaltyExemptList takes a comma-separated list of addresses, wildcards and CIDR ranges; the default is not to exempt any addresses.
- Why is there only one line per source instead of one per failed attempt?
- The message marks a state change — the moment an inactive penalty becomes active. Further penalties from the same source extend the expiry silently, up to the configured maximum, and the code reports those through debug_f, so you only see them if you raise LogLevel, which the manual warns against doing at DEBUG on production hosts.
Run your own auth.log through it
Paste or drop /var/log/auth.log (or journalctl -u ssh output) into the free browser analyzer: brute force, password spraying, a successful login after failures and invalid-user sweeps are flagged with the evidence lines. Nothing is uploaded.