Overview
The “Failed to retrieve directory listing” error shows up in FTP clients like FileZilla, Cyberduck, or WinSCP right after a successful login. You connect fine, credentials are accepted, and then — nothing. The directory never loads and the connection stalls or drops.
This happens on Linux servers because FTP uses two separate channels: a control channel (port 21) for commands, and a data channel for actually transferring file listings and content. When something blocks or misconfigures that data channel — a firewall rule, a NAT layer, SELinux, or a misconfigured FTP daemon — the login works but the listing fails. The error itself is annoyingly vague and the same message can have four or five completely different root causes depending on your environment.
This article covers cPanel/WHM servers running Pure-FTPd or vsftpd on CentOS/AlmaLinux/CloudLinux, but the underlying logic applies to any Linux hosting setup. If you’re on a VPS SSD Hosting plan and managing your own firewall, pay close attention to the passive port range section — that’s the most common culprit on VPS environments.
Prerequisites
- Root SSH access to the server, or WHM access with full admin privileges
- An FTP client installed locally (FileZilla 3.x or later recommended for testing)
- Basic familiarity with the Linux command line
- Knowledge of which FTP daemon your server runs — Pure-FTPd (cPanel default) or vsftpd
- If you’re behind a corporate network or VPN, confirm you can test from a standard residential connection — some office firewalls block FTP data ports entirely
Step-by-Step Instructions
Step 1: Switch Your FTP Client to Passive Mode
This fixes the problem in the majority of cases and takes 30 seconds to try. In active mode, the server initiates the data connection back to your client. Most home routers and firewalls block incoming connections, so the data channel never opens.
In FileZilla:
- Go to Edit > Settings > Connection > FTP
- Set Transfer Mode to Passive
- Click OK, disconnect, and reconnect
If you’re connecting via an explicit FTPS or SFTP connection instead, passive mode works differently — but for standard FTP on port 21, this one change resolves it for most end users.
Step 2: Open the Passive Port Range in WHM Firewall (CSF)
Passive mode requires a range of high-numbered ports to be open on the server side. If those ports are blocked by ConfigServer Firewall (CSF) — which is the default firewall on most cPanel servers — the data channel can’t open even in passive mode.
First, check which passive port range your FTP daemon is configured to use:
# For Pure-FTPd (cPanel default)
grep -i passivedports /etc/pure-ftpd.conf
# For vsftpd
grep -i pasv /etc/vsftpd.conf
If nothing is configured, Pure-FTPd defaults to 30000–50000. Now open those ports in CSF:
vi /etc/csf/csf.conf
Find the TCP_IN line and add the passive range:
TCP_IN = "20,21,22,25,53,80,110,143,443,465,587,993,995,2077,2078,2082,2083,2086,2087,2095,2096,30000:50000"
Then restart CSF:
csf -r
📝 Note: If you’re running a tighter passive range (e.g. 49152–65534), configure it in /etc/pure-ftpd.conf first, then match it in CSF. Don’t open a wide port range in the firewall without also locking down the daemon to that same range.
Step 3: Configure the Passive Port Range in Pure-FTPd
Even if the firewall is open, Pure-FTPd needs to know which ports it’s allowed to use for passive connections. Without this, it may try to assign ports that your firewall blocks.
echo "30000 50000" > /etc/pure-ftpd/conf/PassivePortRange
service pure-ftpd restart
For vsftpd, edit /etc/vsftpd.conf directly:
pasv_min_port=30000
pasv_max_port=50000
pasv_enable=YES
Then restart:
systemctl restart vsftpd
Step 4: Set the Passive IP Address (NAT / Cloud Environments)
This is the gotcha that catches most people on VPS and cloud servers. When your server is behind NAT — which is the case on most virtualised environments including many VPS setups — the FTP daemon reports its private internal IP in the PASV response. Your FTP client then tries to connect to a non-routable private address like 10.x.x.x or 192.168.x.x, which obviously fails from the outside.
You need to force Pure-FTPd to advertise the server’s public IP:
echo "YOUR.PUBLIC.IP.HERE" > /etc/pure-ftpd/conf/ForcePassiveIP
service pure-ftpd restart
For vsftpd, add this to /etc/vsftpd.conf:
pasv_address=YOUR.PUBLIC.IP.HERE
pasv_addr_resolve=NO
⚠ Warning: If your server’s public IP changes (some VPS providers don’t assign static IPs on cheaper plans), this will break again. I’d recommend confirming you have a static IP before relying on this setting long-term.
Step 5: Check SELinux (AlmaLinux / CentOS)
If you’re on AlmaLinux 8/9 or CentOS with SELinux enforcing, it can block FTP data connections silently — the daemon thinks everything is fine but SELinux denies the actual port binding.
# Check SELinux status
getenforce
# Check for FTP-related denials
grep ftp /var/log/audit/audit.log | tail -20
If you see AVC denials in the audit log related to FTP, enable the correct SELinux booleans:
setsebool -P ftp_home_dir on
setsebool -P ftpd_full_access on
📝 Note: Don’t just set SELinux to permissive mode as a permanent fix. That disables an important security layer across the entire system. Fix the specific boolean instead.
Step 6: Verify with a Raw FTP Session
If you’re still stuck, bypass your FTP client entirely and test with curl. This tells you exactly where the connection fails:
curl -v --ftp-pasv ftp://username:password@yourdomain.com/
Look at the output. If you see 227 Entering Passive Mode followed by a timeout, the port isn’t open. If you never see the 227 response, the issue is at the control channel or authentication level.
Common Issues & Troubleshooting
Connection Established but Directory Listing Hangs Indefinitely
Cause: The control channel connected successfully (port 21), but the data port is being silently dropped by the firewall — not rejected, just dropped. This causes the client to wait until it times out rather than throwing an immediate error.
Fix: Check that your passive port range is open in both CSF/iptables AND that the range is configured in the FTP daemon. Run csf -l | grep 30000 to confirm CSF has the rule active, not just configured.
Error: “ECONNREFUSED – Connection refused by server”
Cause: Usually means the FTP service itself isn’t running, or it’s listening on a non-standard port.
Fix:
systemctl status pure-ftpd
netstat -tlnp | grep :21
If Pure-FTPd isn’t running, check /var/log/messages or journalctl -xe for why it failed to start. A malformed config file in /etc/pure-ftpd/conf/ is a frequent cause.
FTP Works on Port 21 but FTPS (Port 990) Fails
Cause: Implicit FTPS on port 990 requires a separate firewall rule and TLS configuration. Most cPanel setups use explicit FTPS over port 21, not implicit FTPS on 990. Your client may be configured for the wrong mode.
Fix: In FileZilla, set the protocol to FTP with Require explicit FTP over TLS, not FTPS. Also confirm port 990 is open in CSF if you genuinely need implicit FTPS.
Only Certain FTP Accounts Get the Error — Not All
Cause: This almost always points to a chroot jail or home directory permission issue on a specific account. Pure-FTPd’s chroot can fail silently if the user’s home directory has world-writable permissions.
Fix:
stat /home/username
chmod 755 /home/username
Pure-FTPd will refuse to chroot into a directory that’s writable by others — it’s a security measure. The directory must be owned by root or the user, with permissions 755 at most.
Error Appears Only From Certain Networks or Locations
Cause: Some ISPs, corporate networks, and VPNs block FTP data ports or intercept FTP traffic with a broken ALG (Application Layer Gateway). This is outside your server’s control.
Fix: Ask the affected user to test from a different network (mobile hotspot works well for this). If it works from a different connection, the problem is their network’s FTP filtering. The better long-term solution is to move those users to SFTP on port 22, which works through virtually every network and is more secure anyway.
FAQ
Frequently Asked Questions
Why does my FTP login succeed but the directory listing fails?
FTP uses two separate connections — one for commands (port 21) and one for transferring data like directory listings. Your login goes through the command channel, which is open, but the data channel is blocked by a firewall, NAT issue, or passive mode misconfiguration. Switching your FTP client to passive mode and opening the passive port range on the server fixes this in most cases.
What ports do I need to open for FTP to work on a cPanel server?
You need port 21 open for the control connection, and a passive port range open for data transfers — typically 30000 to 50000 on cPanel servers running Pure-FTPd. Both ranges need to be open in your firewall (CSF or iptables) and configured in the FTP daemon itself. If you’re using SFTP instead, you only need port 22.
Should I use FTP or SFTP for uploading files to my hosting account?
SFTP is the better choice for almost every situation. It runs over SSH on port 22, encrypts both credentials and file data, and works through most firewalls without the passive port headaches that standard FTP requires. All cPanel accounts support SFTP using your cPanel username and password — you don’t need to set anything up separately.
Can a security plugin or WAF cause the 'failed to retrieve directory listing' error?
A WAF (Web Application Firewall) operating at the HTTP layer won’t affect FTP connections directly since they use different ports and protocols. However, firewall tools like CSF with LFD (Login Failure Daemon) can temporarily block your IP after repeated failed FTP login attempts. If you were troubleshooting and tried multiple wrong passwords, run ‘csf -g YOUR.IP’ to check if you’ve been blocked, and ‘csf -ar YOUR.IP’ to remove the block.
I set the passive port range in CSF but it still doesn't work — what am I missing?
The most common miss is that CSF was updated in the config file but not reloaded — changes to csf.conf don’t take effect until you run ‘csf -r’. The second common miss is a mismatch between the range configured in CSF and the range configured in the FTP daemon itself. Both need to match exactly. If you’re on a cloud VPS or a server behind NAT, you also need to set ForcePassiveIP in Pure-FTPd to your server’s public IP address.