Control panels

Using lsof to identify processes consuming high amounts of server resources

Use the lsof command to find which process holds a port, file or deleted log open on your Linux VPS, and fix the resource problem at its source.

IntermediateLinux server6 min read

The lsof command lists every file a process has open — and on Linux that includes sockets, pipes and devices. If a port is busy, a log file will not rotate, or a disk stays full after you delete files, lsof tells you which process is responsible. This guide walks through the commands that answer those questions fast, on Ubuntu, Debian, AlmaLinux and Rocky.

Before you start

You need SSH access to the VPS and a user that can run commands with sudo. lsof only shows other users' processes when you run it as root, so prefix almost everything here with sudo.

Check what you have:

Bash
lsb_release -a 2>/dev/null || cat /etc/os-release
lsof -v

If lsof -v prints nothing, install it:

Bash
sudo apt update && sudo apt install -y lsof     # Ubuntu 22.04/24.04, Debian 12
sudo dnf install -y lsof                        # AlmaLinux / Rocky 8-9

Tip: Always add -n (no DNS lookups) and -P (no port-name lookups) to network queries. On a busy VPS those two flags turn a 30-second wait into instant output.

Run your first listing

Bare lsof dumps everything, which is noisy. Start with a count so you know how much is open:

Bash
sudo lsof -nP | wc -l
sudo lsof -u deploy -nP | wc -l

The columns you care about:

  • COMMAND and PID — the process name and its process ID.
  • USER — who owns it.
  • FD — the file descriptor type: cwd (current directory), txt (executable), mem (memory-mapped), a number for data files.
  • TYPE — REG for regular file, DIR, IPv4, IPv6, unix.
  • NAME — the path, or the socket address in local:remote form.

To see one process in full rather than truncated names:

Bash
sudo lsof -p 4821
sudo lsof -p 4821 +c 0

Find which process is using a port

This is the most common reason people reach for lsof — a service refuses to start with "Address already in use".

Bash
sudo lsof -nP -i :80
sudo lsof -nP -i :443

To list only listeners:

Bash
sudo lsof -nP -i -sTCP:LISTEN

To check whether a specific process opened a connection outbound:

Bash
sudo lsof -nP -i TCP -a -c nginx

The -a operator is important: it ANDs the filters together instead of ORing them. Without it you get every nginx file plus every TCP socket on the box.

When you only want process IDs, for example to feed into another command:

Bash
sudo lsof -t -i :8080

Warning: Never run kill -9 on a process just because it holds a port. Stop it properly first (sudo systemctl stop <service>) so it flushes state and releases its lock files.

Find which process holds a file open

To see what is using a single file:

Bash
sudo lsof /var/log/syslog

To scan a whole directory tree, for example before unmounting a volume:

Bash
sudo lsof +D /var/www
sudo lsof +D /mnt/data

+D recurses and can be slow on large trees. +d checks only the directory itself.

If a user cannot empty their home directory because something is holding files, filter by user and path together:

Bash
sudo lsof -u deploy -nP +d /home/deploy

Reclaim disk space held by deleted files

A process that keeps a log file open after you delete it still occupies the inode, so df reports the disk as full. That is why deleting a big log sometimes frees nothing. Find those files:

Bash
sudo lsof -nP +L1

Look for a LINK count below 1 and a large SIZE/OFF, with NAME ending in (deleted). A common case is a rotated Nginx or PHP-FPM log held by a worker:

nginx   2211 www-data   4w   REG  253,0 4123456789  131074 /var/log/nginx/access.log (deleted)

The fix is to make the process reopen its files, not to delete more files:

Bash
sudo systemctl reload nginx
sudo systemctl restart php8.3-fpm     # adjust to your PHP version

Warning: Do not truncate a deleted file through /proc/<pid>/fd unless you are certain nothing is writing to it. On a live log you can lose buffered data and confuse the application's offset tracking.

Handle "too many open files"

When a service throws EMFILE: too many open files, count what it actually holds:

Bash
sudo lsof -u www-data -nP | wc -l
sudo lsof -p $(pgrep -f 'php-fpm: pool www' | head -1) | wc -l

Compare that with the limit in force:

Bash
cat /proc/$(pgrep -f 'php-fpm: master' | head -1)/limits | grep -i 'open files'

If the count sits near the limit, raise it in the systemd unit rather than only in limits.conf:

INI
[Service]
LimitNOFILE=65535

Then reload and restart:

Bash
sudo systemctl daemon-reload
sudo systemctl restart php8.3-fpm

Note: lsof is a snapshot, not a monitor. Run it two or three times a minute apart to confirm a file descriptor count is genuinely climbing.

Check it works

Pick a listening port you know is in use, such as SSH on 22:

Bash
sudo lsof -nP -i :22

You should see the sshd process, its PID and a LISTEN state. Now confirm the same PID appears for that user:

Bash
sudo lsof -u root -nP | grep LISTEN | head

Then verify the deleted-file check runs cleanly on a quiet system — no output means nothing is holding an unlinked file open, which is normal:

Bash
sudo lsof -nP +L1

If all three behave as described, lsof is installed and you are reading it correctly. You can also confirm resource pressure from your VPS provider's control panel, where the browser console and power controls let you act on a service that will not respond over SSH.

Troubleshooting

  • lsof: command not found — the package is missing. Install lsof with apt or dnf as shown above; some minimal cloud images ship without it.
  • lsof hangs or takes minutes — it is resolving names and scanning large trees. Add -nP, narrow with -p, -u or +d instead of +D, and avoid running it against NFS mounts when they are unresponsive.
  • A port responds but lsof shows nothing — either you are not root, or the socket belongs to a container in its own network namespace. Run sudo lsof -nP -i inside the container, or compare against ss -tulpn on the host.
  • Command names are cut off, so you cannot tell two workers apart — use sudo lsof +c 0 -p <pid> to print full command lines.
  • lsof reports "can't stat" or permission denied on some entries — expected for paths you cannot read. Anything you truly need will appear when you run it with sudo.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.