Nothing makes you doubt your own competence like an SSH login that just… waits. You type a password (or your key is accepted), and then the session pauses long enough to question your life choices. The server isn’t down. CPU is fine. Disk is fine. Yet your prompt arrives with the urgency of a fax machine.
This case is about Debian 13 and a very specific kind of slow: the delay between “TCP connected” and “I have a shell.” The culprits are almost always boring: DNS reverse lookups (UseDNS) and GSSAPI/Kerberos negotiation. They don’t break SSH; they just make it feel haunted. We’ll pin down which one is biting you, prove it with timings, and fix it safely.
Fast diagnosis playbook
If you only have five minutes (and you do), don’t “optimize SSH.” Identify the stall. Then fix the one knob that matches the stall.
First: time the login from the client (find the phase)
Run SSH with maximal verbosity and watch where it pauses. If it freezes after “Authentications that can continue” or around GSSAPI lines, that’s one path. If it freezes after authentication, before the shell, that’s often DNS or PAM name service lookups.
Second: check the server logs during the stall
In another terminal, tail the server’s journal for sshd. If you see “reverse mapping checking getaddrinfo…” or long gaps between log lines, that’s DNS. If you see “GSSAPI” and repeated attempts, that’s Kerberos/GSSAPI negotiation.
Third: prove DNS is slow (forward + reverse)
From the server, resolve the client IP to a PTR, then resolve that hostname back. If either query takes seconds or times out, you’ve found the delay.
Fourth: apply the minimal safe fix
- For DNS reverse lookup stalls: set
UseDNS noin/etc/ssh/sshd_config(or a drop-in) and restart sshd. - For GSSAPI stalls: set
GSSAPIAuthentication no(client and/or server) where Kerberos isn’t required.
Fifth: retest and roll back if you changed the wrong thing
SSH slowness is usually deterministic. If you fix the right cause, it becomes instantly fast. If it becomes “different slow,” you’re now debugging something else (PAM, LDAP, home dir mounts, shell profile scripts).
What “slow SSH login” actually means
When people say “SSH is slow,” they usually mean one of four delays:
- TCP connect is slow: you can’t establish a connection quickly. That’s routing, firewall, SYN drops, or IP version selection.
- Key exchange is slow: crypto negotiation stalls. Rare on modern hardware unless entropy is broken or the network is mangling packets.
- Authentication is slow: the server takes ages to check your key/password. Often PAM + LDAP/SSSD, or GSSAPI.
- Post-auth is slow: authentication succeeds, then you wait before getting a shell. Commonly DNS reverse lookups, PAM session modules, automounts, or shell startup scripts.
This article is about cases where connect is fast, key exchange is fast, but you still sit there waiting—usually because the server is politely trying to know your name (DNS) or your enterprise identity (Kerberos), and waiting for someone else’s infrastructure to answer.
One principle worth keeping: don’t guess. SSH gives you enough observability to identify the exact pause with timestamps and logs. Use them.
Reliability engineer John Allspaw has a paraphrased idea I like: Operations succeeds when you understand the system you actually have, not the one you imagined.
That’s this entire problem in one sentence.
Interesting facts and context (why this keeps happening)
- OpenSSH added GSSAPI support decades ago to fit into Kerberos-heavy enterprise networks where “passwordless” means tickets, not keys.
- Reverse DNS checks in sshd are older than most current cloud networks; they made sense when host-based trust and logging by hostname were common.
- DNS timeouts are often “slow by design”: resolvers retry multiple servers, over UDP then TCP, across search domains, with backoff.
- A missing PTR record can be worse than a wrong PTR: wrong answers are fast; timeouts are slow.
- nsswitch controls far more than people think: if
hosts:includes mdns, nis, or files ordering badly, a “simple lookup” becomes a tour of your network’s regrets. - systemd-resolved changed the debugging surface: you’re often talking to a local stub resolver, which then talks to upstream resolvers with its own caching and failure behaviors.
- SSH client defaults can trigger server-side work: a client offering GSSAPI can make a server attempt it, even if it will never succeed.
- IPv6 can add seconds of delay without breaking anything: AAAA lookups, unreachable v6 resolvers, or broken v6 routes can create “mystery pauses.”
Two takeaways: (1) most SSH “performance problems” are actually name service performance problems, and (2) the right fix is usually a single-line config change, once you prove the cause.
Practical tasks: commands, outputs, decisions
These are not lab commands. They’re the ones you run on a Tuesday at 02:10 while someone pings “is prod ok?” Each task includes what the output means and what decision you make from it.
Task 1: Measure where the client pauses (SSH verbose)
cr0x@server:~$ ssh -vvv admin@debian13-prod
OpenSSH_9.9p1 Debian-1, OpenSSL 3.3.2 3 Sep 2025
debug1: Connecting to debian13-prod [10.20.30.40] port 22.
debug1: Connection established.
debug1: identity file /home/admin/.ssh/id_ed25519 type 3
debug1: kex: algorithm: sntrup761x25519-sha512
debug1: SSH2_MSG_NEWKEYS sent
debug1: SSH2_MSG_NEWKEYS received
debug1: Authenticating to debian13-prod:22 as 'admin'
debug1: Offering public key: /home/admin/.ssh/id_ed25519
debug1: Server accepts key: /home/admin/.ssh/id_ed25519
debug1: Authentication succeeded (publickey).
debug1: Entering interactive session.
debug1: pledge: filesystem
... (pause here for 6 seconds) ...
Linux debian13-prod 6.12.0-1-amd64 #1 SMP Debian 6.12.3-1 ...
admin@debian13-prod:~$
Meaning: crypto and auth are fast; the pause is after “Entering interactive session.” That points to post-auth steps: reverse DNS, PAM session modules, automounts, or shell init. DNS is a prime suspect.
Decision: Check server logs and DNS resolution from the server next.
Task 2: Tail sshd logs while reproducing the issue
cr0x@server:~$ sudo journalctl -u ssh -f
Dec 30 11:18:02 debian13-prod sshd[23144]: Accepted publickey for admin from 10.20.99.17 port 51244 ssh2: ED25519 SHA256:...
Dec 30 11:18:02 debian13-prod sshd[23144]: pam_unix(sshd:session): session opened for user admin(uid=1000) by (uid=0)
Dec 30 11:18:08 debian13-prod sshd[23144]: pam_env(sshd:session): deprecated reading of user environment enabled
Meaning: There’s a six-second gap between session opened and the next log line. That is the stall window.
Decision: Check whether sshd is doing DNS lookups or GSSAPI attempts, and test name resolution latency.
Task 3: Identify client IP from logs, then test reverse DNS on the server
cr0x@server:~$ dig +tries=1 +time=2 -x 10.20.99.17
;; communications error to 10.20.0.53#53: timed out
;; communications error to 10.20.0.54#53: timed out
;; no servers could be reached
Meaning: Reverse lookup is timing out. sshd may be waiting for this during login if UseDNS is enabled or if other components do lookups.
Decision: Fix resolver reachability or disable reverse DNS usage in sshd (depending on policy). Keep digging: is DNS broken on the server or just for that subnet?
Task 4: Check what resolver the server is using (systemd-resolved)
cr0x@server:~$ resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 10.20.0.53
DNS Servers: 10.20.0.53 10.20.0.54
DNS Domain: corp.example
Meaning: The server relies on 10.20.0.53/54. If those are unreachable from this host/VRF, DNS queries will stall.
Decision: Verify reachability to resolvers and consider local caching behavior and timeouts.
Task 5: Confirm reachability to DNS servers (don’t assume)
cr0x@server:~$ ping -c 2 10.20.0.53
PING 10.20.0.53 (10.20.0.53) 56(84) bytes of data.
--- 10.20.0.53 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1009ms
Meaning: Your resolver is dead to this host. That’s not an SSH problem; it’s a dependency problem.
Decision: Fix routing/firewall to DNS, or temporarily point this host at a reachable resolver; then revisit sshd’s UseDNS policy.
Task 6: Check if sshd is configured to use reverse DNS
cr0x@server:~$ sudo sshd -T | egrep 'usedns|gssapiauthentication|gssapicleanupcredentials|gssapikexalgorithms'
usedns yes
gssapiauthentication yes
gssapicleanupcredentials yes
Meaning: sshd is explicitly doing reverse DNS checks and will also attempt GSSAPI authentication.
Decision: If you don’t require reverse-DNS-based hostname logging or host-based auth, set UseDNS no. If you don’t use Kerberos SSH, disable GSSAPI. But validate first which one is causing your pause.
Task 7: Time DNS forward and reverse lookups (fast/slow proof)
cr0x@server:~$ time getent hosts 10.20.99.17
10.20.99.17 laptop17.corp.example
real 0m5.912s
user 0m0.003s
sys 0m0.003s
Meaning: A basic resolver path is taking ~6 seconds, matching the login stall. That’s your smoking crater.
Decision: Either fix DNS reachability/records, or tell sshd not to block on this lookup.
Task 8: Verify PTR → A/AAAA forward-confirmed reverse DNS (FCRDNS)
cr0x@server:~$ host 10.20.99.17
17.99.20.10.in-addr.arpa domain name pointer laptop17.corp.example.
cr0x@server:~$ host laptop17.corp.example
laptop17.corp.example has address 10.20.99.18
Meaning: PTR points to a hostname that doesn’t resolve back to the same IP. This mismatch can cause extra lookups and confusion in logs, and some systems treat it suspiciously.
Decision: Fix the PTR or A record if you rely on reverse DNS for logging/auditing. If you don’t, disable UseDNS and stop paying this tax.
Task 9: Disable UseDNS safely using a drop-in file
cr0x@server:~$ sudo install -d -m 0755 /etc/ssh/sshd_config.d
cr0x@server:~$ printf "UseDNS no\n" | sudo tee /etc/ssh/sshd_config.d/10-fast-login.conf
UseDNS no
cr0x@server:~$ sudo sshd -t
cr0x@server:~$ sudo systemctl restart ssh
cr0x@server:~$ sudo systemctl is-active ssh
active
Meaning: Config syntax is valid, service restarted cleanly.
Decision: Re-test SSH timing. If it becomes instant, you’ve isolated the problem to DNS reverse lookups during login.
Task 10: Confirm the improvement from the client
cr0x@server:~$ ssh -vv admin@debian13-prod
debug1: Authentication succeeded (publickey).
debug1: Entering interactive session.
Linux debian13-prod 6.12.0-1-amd64 #1 SMP Debian 6.12.3-1 ...
admin@debian13-prod:~$
Meaning: The pause is gone. Good. Keep going anyway: DNS is still broken, you just stopped SSH from waiting on it.
Decision: Create a ticket for resolver reachability/PTR hygiene. You don’t want other services to hang.
Task 11: Detect GSSAPI negotiation delays from the client
cr0x@server:~$ ssh -vvv user@debian13-prod
debug1: Authentications that can continue: publickey,gssapi-with-mic,password
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure. Minor code may provide more information
debug1: No Kerberos credentials available (default cache: FILE:/tmp/krb5cc_1000)
... (pause and retries) ...
debug1: Next authentication method: publickey
debug1: Offering public key: /home/user/.ssh/id_ed25519
debug1: Authentication succeeded (publickey).
Meaning: The client is attempting GSSAPI first, failing, and burning time doing it. Even if publickey is fast, you’re paying the GSSAPI attempt penalty.
Decision: Disable GSSAPI on the client for this host (preferred) or on the server if your environment doesn’t use Kerberos SSH.
Task 12: Disable GSSAPI on the client (per-host) without changing the server
cr0x@server:~$ cat >> ~/.ssh/config <<'EOF'
Host debian13-prod
GSSAPIAuthentication no
PreferredAuthentications publickey
EOF
cr0x@server:~$ ssh -vv user@debian13-prod
debug1: Authentications that can continue: publickey,password
debug1: Offering public key: /home/user/.ssh/id_ed25519
debug1: Authentication succeeded (publickey).
Meaning: No GSSAPI attempt; the authentication path is shorter.
Decision: If this consistently fixes the delay for users, consider server-side policy too—after confirming nobody depends on Kerberos SSH.
Task 13: Disable GSSAPI on the server (only if you don’t use Kerberos SSH)
cr0x@server:~$ printf "GSSAPIAuthentication no\n" | sudo tee /etc/ssh/sshd_config.d/20-no-gssapi.conf
GSSAPIAuthentication no
cr0x@server:~$ sudo sshd -t
cr0x@server:~$ sudo systemctl restart ssh
cr0x@server:~$ sudo sshd -T | egrep 'gssapiauthentication|usedns'
usedns no
gssapiauthentication no
Meaning: Server will not offer GSSAPI. This can materially reduce “first auth method” churn.
Decision: Roll this only after verifying your fleet doesn’t use Kerberos tickets for SSH SSO.
Task 14: Check host lookup order (nsswitch) when “DNS is fine but getent is slow”
cr0x@server:~$ grep '^hosts:' /etc/nsswitch.conf
hosts: files mdns4_minimal [NOTFOUND=return] dns
Meaning: mDNS is being queried before DNS. In server environments, mDNS is usually dead weight and can introduce delays, especially with weird network setups.
Decision: Consider simplifying hosts resolution on servers (often files dns), but coordinate with whatever installed mdns in the first place.
Task 15: Prove whether systemd-resolved is the bottleneck (cache vs upstream)
cr0x@server:~$ resolvectl query -t PTR 10.20.99.17
10.20.99.17: resolve call failed: No appropriate name servers or networks for name found
Meaning: resolved can’t reach configured DNS for that query. That’s not a “slow query,” it’s a “no path to DNS” issue, which often manifests as timeouts elsewhere.
Decision: Fix networking to DNS or adjust DNS servers for that interface/VLAN.
Task 16: Confirm the stall isn’t from PAM/SSSD/LDAP (a common decoy)
cr0x@server:~$ sudo pam_tally2 --user admin
Login Failures Latest failure From
admin 0
Meaning: Nothing obvious here, but the point is: check whether PAM modules are doing external calls. (On many systems you’d instead inspect /etc/pam.d/sshd and SSSD logs.)
Decision: If disabling UseDNS and GSSAPI doesn’t fix it, pivot to PAM/session and directory services.
DNS reverse lookup delays: the classic “why is SSH polite?” failure
Reverse DNS is the #1 reason SSH “works but feels slow.” sshd receives a client IP and—depending on configuration—tries to resolve it to a hostname, then sometimes verify that the hostname resolves back to the same IP. If DNS is slow or broken, sshd waits.
Here’s the uncomfortable truth: in many environments, reverse DNS is not maintained with the same discipline as forward DNS. People add A/AAAA records because things won’t work otherwise. PTRs are treated as a “nice to have” until something blocks on them. sshd is one of those things.
What UseDNS actually does (and what it does not)
UseDNS controls whether sshd uses DNS to map the remote IP to a hostname for logging and access control decisions involving hostnames. If you disable it, sshd will typically log and operate based on the IP address instead of waiting on reverse DNS.
Disabling UseDNS does not prevent everything from doing DNS lookups. PAM modules, audit tooling, and your shell prompt might still resolve names. But it removes one common synchronous delay right in the login path.
Why this gets worse in modern networks
Cloud and corporate networks love indirection: overlay networks, split-horizon DNS, multiple resolvers per interface, and security appliances that intercept DNS. Each layer adds failure modes that look like “it’s only slow sometimes.” SSH makes those failure modes painfully visible because it’s interactive and you notice every second.
And yes, IPv6 deserves special mention. Dual-stack misconfigurations often cause “attempt v6 first, fail slowly, then succeed v4.” Sometimes you won’t even see it in your logs unless you’re looking.
Fix strategy: decide whether you need reverse DNS in sshd
Ask an adult question: do you actually need reverse DNS lookups during SSH login?
- If you use host-based access rules with hostnames in
AllowUsers/DenyUserspatterns or match blocks, reverse DNS might matter. In practice, this is rare and often brittle. - If you rely on hostname logging for incident response, you may think you want it. But IP addresses are usually more reliable than PTRs in messy networks. You can always do reverse lookups offline when DNS is healthy.
- If you do not have disciplined PTR management, enabling UseDNS is a tax you pay forever.
My bias: on servers, disable UseDNS unless you have a specific, tested reason not to. Keep the dependency chain short.
Joke #1: DNS is like office politics—when it’s healthy, you don’t notice it; when it’s broken, everything becomes a meeting.
What if you must keep UseDNS enabled?
Then treat PTR records as production data. Maintain them. Monitor them. Test them from the server subnets that matter. And make sure the servers can reach their resolvers quickly and consistently.
Also: set realistic resolver timeouts. Some environments accept long DNS timeouts “because eventually it works.” Interactive logins don’t.
GSSAPI/Kerberos delays: the enterprise tax you might not owe
GSSAPI in SSH exists so you can authenticate using Kerberos tickets. In the right environment it’s great: single sign-on, centralized policy, fewer SSH keys sprawl. In the wrong environment it’s a slow, failing preflight check on every login.
When GSSAPI is enabled, a client and server may attempt one or more Kerberos exchanges before falling back to public key or password. If the client lacks tickets, if the KDC is unreachable, if reverse DNS for realms is broken, or if time sync is off, you can get seconds of delay per attempt.
How to recognize GSSAPI slowness
The client verbose output usually shows it clearly: it tries gssapi-with-mic, fails with “No Kerberos credentials” or similar, and only then offers a key. Sometimes it retries. Sometimes it waits on DNS SRV lookups for KDCs. Sometimes it waits on network timeouts to the KDC.
Unlike UseDNS, GSSAPI slowness is often visible in the authentication phase, before “Entering interactive session.” That’s how you tell them apart quickly.
Fix strategy: disable where appropriate, don’t sabotage SSO accidentally
There are two safe patterns:
- Client-side per-host disablement (
~/.ssh/config) for hosts where Kerberos is not used. This avoids breaking other hosts where Kerberos SSH is desired. - Server-side disablement when you are confident the environment does not use Kerberos SSH at all. This prevents clients from even attempting it.
Be careful with blanket changes in shared corporate environments. Someone, somewhere, is using that feature you forgot existed. They are also usually a director with a tight calendar.
Joke #2: Kerberos is wonderful until it isn’t, at which point it becomes a distributed system with feelings.
GSSAPI cleanup and credential forwarding
Options like GSSAPICleanupCredentials and client-side credential forwarding can matter for security and user experience, but they’re usually not the primary cause of “login is slow.” If your delay is during authentication and GSSAPI is enabled, start by determining whether it’s failing and timing out, or succeeding quickly.
If you do use Kerberos, then treat the KDC path as a dependency: DNS, time sync, firewall rules, and realm configuration must be boringly correct. SSH is just the messenger.
Three corporate mini-stories from the trenches
1) The incident caused by a wrong assumption: “DNS is always there”
A mid-size company migrated a batch of Debian hosts into a “restricted” network segment. The segment had strict egress rules: only application ports, no “random infrastructure.” Someone assumed DNS would be handled “by the platform,” because it had always been true in other segments. The hosts came up with resolvers pointing to corporate DNS, but the firewall didn’t allow port 53 to those IPs from that VLAN.
Everything looked fine in dashboards. CPU was idle. Services were running. But engineers noticed SSH logins taking 5–15 seconds. They wrote it off as “VPN slowness,” until an on-call tried to debug a production issue and spent the entire incident waiting for shells.
The real damage wasn’t the delay itself; it was the behavior it created. People opened more sessions “because the first one hung.” Bastion hosts got hammered. SSH connection tracking grew. The incident response felt chaotic because the tools were sluggish.
The fix was painfully simple: allow DNS egress to the resolvers or place a resolver inside the segment. Disabling UseDNS made SSH snappy immediately, but the team still had to fix DNS because other components (package installs, TLS validation, service discovery) were also skating on thin ice. The lesson was not “turn off UseDNS.” The lesson was “validate dependencies from the network where the server actually lives.”
2) The optimization that backfired: “Let’s make DNS more secure”
A security team rolled out a new DNS policy: all hosts should use a pair of “secure resolvers” that performed filtering and logging. They pushed the change via configuration management. The resolvers were fine—until they weren’t. Under certain failure modes, the filtering layer would accept packets but delay responses while attempting upstream validation.
SSH became the canary. Engineers reported that logging into production hosts sometimes took ten seconds, but only during business hours. The immediate reaction was to blame encryption: “Maybe the new OpenSSH build is slower.” Someone suggested changing ciphers. Someone else suggested disabling compression. None of it helped, because crypto wasn’t the problem.
A careful SRE compared ssh verbose timings to DNS query times and found that reverse lookups were stalling exactly when the secure resolvers were under load. Even worse, the load correlated with security scanning windows that generated a flood of unknown domains—exactly what the filtering service had to analyze. The system was doing its job; it was just doing it synchronously for interactive logins.
The eventual fix was twofold: (1) disable UseDNS fleetwide for servers, and (2) tune the secure resolver path so that timeouts failed fast and caches were sized appropriately. Security got their logs. SRE got their shells back. The backfire wasn’t “security is bad.” It was “interactive systems can’t wait for your compliance pipeline.”
3) The boring but correct practice that saved the day: staged SSH config with measurable rollouts
A different company ran a large Debian fleet with strict change control, which sounds annoying until it saves you. They had a standard: every sshd change must be (a) applied via drop-in files, (b) validated with sshd -t, and (c) rolled out to a small canary set before expanding.
When a new environment started reporting slow SSH, the team didn’t immediately “fix SSH.” They gathered evidence: client -vvv logs, server journal gaps, and DNS timing from getent. They confirmed reverse DNS lookups were taking several seconds due to missing PTR records for a new VPN address pool.
The boring practice was that they already had an approved drop-in for performance-sensitive hosts: /etc/ssh/sshd_config.d/10-fast-login.conf with UseDNS no. It had been reviewed, tested, and documented. They deployed it to the impacted segment first, verified improvement, then filed the DNS PTR work as a separate track.
Nothing dramatic happened. No one got paged twice. That’s what “saved the day” looks like in real operations: fewer surprises, fewer late-night heroics, more systems that behave like you expect.
Common mistakes: symptoms → root cause → fix
This is the section you want when you’re tired and slightly angry at computers.
1) Symptom: long pause after “Authentication succeeded”
Root cause: reverse DNS lookup during session setup (UseDNS yes) timing out or slow resolver.
Fix: set UseDNS no in sshd; also fix resolver reachability and PTR hygiene.
2) Symptom: long pause before key is offered; verbose shows “gssapi-with-mic” attempts
Root cause: GSSAPI authentication enabled; client tries Kerberos first, waits on KDC/DNS/timeouts.
Fix: disable GSSAPIAuthentication on the client per-host or server-wide if Kerberos SSH isn’t used.
3) Symptom: fast on LAN, slow from VPN
Root cause: VPN address pool lacks PTR records, or VPN clients resolve via a different DNS path; reverse lookups time out.
Fix: add PTRs for VPN pool or disable UseDNS; verify DNS reachability from server to resolvers handling that reverse zone.
4) Symptom: only some servers are slow, others fine
Root cause: per-subnet DNS ACLs, different resolvers per interface, or split-horizon zones missing in one view.
Fix: compare resolvectl status and resolver reachability between hosts; align DNS configuration per network segment.
5) Symptom: SSH slow only for some usernames
Root cause: PAM modules hitting LDAP/SSSD/automount for those users; not primarily DNS/GSSAPI.
Fix: inspect /etc/pam.d/sshd, SSSD logs, and home directory mount behavior; test with a local user.
6) Symptom: “ssh is slow” but ssh -vvv shows delay before “Connection established”
Root cause: network path latency, firewall SYN rate limits, or name resolution of the target host (client-side DNS), not server-side login steps.
Fix: SSH to IP directly, test with nc -vz, and verify client DNS vs server DNS.
7) Symptom: SSH is slow after login (prompt appears, then commands lag)
Root cause: shell startup scripts doing network calls (git prompt, kubectl context, LDAP queries), or networked home directories.
Fix: profile the shell init path; temporarily test with ssh user@host /bin/bash --noprofile --norc.
8) Symptom: disabling UseDNS helped, but logs are now “uglier”
Root cause: you previously depended on hostname logs that were derived from PTR records.
Fix: update logging/alerting to key on IP; do reverse lookups asynchronously in log pipelines if you must.
Checklists / step-by-step plan
Plan A: you need SSH fast now (safe and reversible)
- From your client, capture
ssh -vvvoutput and note where it stalls (auth vs post-auth). - On the server, tail
journalctl -u ssh -fwhile reproducing the login. - On the server, run
sshd -T | grep usednsandsshd -T | grep gssapiauthentication. - If the stall is post-auth and DNS is suspect: set
UseDNS novia/etc/ssh/sshd_config.d/. - If the stall is during auth and GSSAPI shows in verbose output: disable GSSAPI per-host in
~/.ssh/config. - Validate config:
sshd -t. - Restart SSH:
systemctl restart ssh. - Re-test from the same client network that was slow (LAN vs VPN matters).
- If fixed, open a follow-up for DNS/Kerberos infrastructure so the next service won’t hang.
Plan B: you must keep reverse DNS and/or Kerberos (do it like an adult)
- Ensure the server can reach its resolvers reliably (ICMP isn’t enough; test UDP/TCP 53 via policy tools if available).
- Ensure PTR records exist for all client subnets (office, VPN, bastions, CI runners).
- Ensure forward-confirmed reverse DNS for critical subnets (PTR points to name; name points back to same IP).
- For GSSAPI: verify KDC reachability, realm config, and time sync; broken NTP will ruin your day quietly.
- Keep retries/timeouts reasonable in the resolver chain so interactive logins fail fast when dependencies are down.
- Measure periodically: store “SSH login time” metrics from representative networks.
Plan C: keep changes minimal and auditable
- Use drop-ins under
/etc/ssh/sshd_config.d/instead of editing the main file. - One change per file (easier rollback).
- Always run
sshd -tbefore restarting. - Keep a console session open during restart if you’re remote, so you don’t lock yourself out.
FAQ
1) Should I always set UseDNS no on Debian 13 servers?
Almost always, yes. Unless you have a specific, tested dependency on reverse-DNS-based hostname decisions in sshd. Most environments don’t, and the cost is real when DNS is flaky.
2) Does disabling UseDNS reduce security?
It removes one class of hostname-based checks, but hostname-based checks are usually weaker than IP- and key-based controls anyway. Don’t use PTR records as an auth signal. Use keys, MFA, network ACLs, and explicit allowlists.
3) Why does SSH do reverse DNS at all?
Legacy and logging convenience. Older operational patterns trusted hostnames more and used them in access controls. Today, networks change faster than PTR records. IPs are often the more honest identifier.
4) If I disable GSSAPI, will I break domain logins?
Not necessarily. Domain users can still authenticate via public keys or passwords depending on your PAM setup. But you will break Kerberos-based SSH SSO if anyone uses it. That’s why client-side per-host disablement is the safest starting point.
5) SSH is slow only on first connection, then fast. Why?
DNS caching (client-side, server-side, or in systemd-resolved) can make subsequent lookups fast. That’s a hint that name service resolution is involved. Time it with getent hosts and compare cold vs warm cache behavior.
6) I set UseDNS no, but it’s still slow after auth. What next?
Pivot to PAM/session and user environment: LDAP/SSSD latency, automounted home directories, slow shell init scripts, or networked filesystem hiccups. Test a local user with a minimal shell to isolate.
7) Can IPv6 cause slow SSH logins even if IPv4 works?
Yes. Dual-stack resolution and reachability issues can add delays in DNS and in contacting identity services. Look for “v6 first then fallback” patterns in verbose logs and resolver status.
8) Should I “fix” it by changing ciphers or KEX algorithms?
No, not for this symptom. If your stall is seconds long and occurs after auth or during GSSAPI, crypto tuning is cargo cult. Measure first; fix the dependency that’s actually slow.
9) Is this specific to Debian 13?
The behavior is general to OpenSSH on many Linux distributions. Debian 13 just means you’re likely on modern OpenSSH and systemd-resolved behavior, which changes where you look for DNS issues.
10) What’s the smallest change that gives the biggest win?
UseDNS no is often the immediate “instant speed” fix for post-auth stalls. For auth stalls, disabling GSSAPI on the client for that host is the smallest and safest.
Conclusion: next steps that stick
If SSH logins on Debian 13 feel slow, treat it like any other production latency: identify the phase, prove the dependency, apply the smallest fix, and then repair the underlying infrastructure so the next service doesn’t inherit the pain.
Do these next:
- Capture one
ssh -vvvsession showing the stall and save it with the timestamp and client network (LAN/VPN/bastion). - On the server, measure
time getent hosts <client-ip>. If it matches the stall, you’re done diagnosing. - Set
UseDNS novia a drop-in, validate withsshd -t, restart, retest. - If verbose output shows GSSAPI churn, disable it per-host on the client first; only disable it server-wide when you’re certain Kerberos SSH isn’t used.
- File the real fix: resolver reachability, PTR record hygiene, and (if relevant) KDC reliability. SSH just exposed the truth.
The end state you want is boring: SSH logs in instantly, DNS works reliably, Kerberos works when you actually use it, and nobody has to learn the hard way that “infrastructure” is a dependency, not a suggestion.