Skip to content
Hosting Operations10 min read

VPS High CPU: 7 Security Fixes That Work (2026)

Fix VPS high CPU by auditing malicious processes, closing attack vectors, and hardening your server. Includes security checklist and verification steps.

Written by Abdul AbrorTechnical Hosting Support Engineer
person holding computer cell processor
On this page

TL;DR — Key takeaways

  • High CPU on a VPS is often caused by compromised accounts running miners, botnets, or mail relays—not just legitimate traffic spikes.
  • Audit running processes with top, htop, and ps to identify unauthorized binaries before attempting performance tuning.
  • Harden SSH access, disable unused services, and implement file integrity monitoring to prevent future CPU-draining attacks.
  • Verify your fixes by monitoring CPU over 24-48 hours and checking for new suspicious processes or network connections.

Your VPS shows 95% CPU usage and the site barely loads. You check the dashboard, restart Apache, maybe add more RAM. Nothing helps.

High CPU on a VPS usually isn't a resource problem. It's a security problem. In support tickets I handled, the pattern repeated: compromised accounts running miners, botnet scripts hammering the network stack, or mail relays pumping spam. This guide walks through the threat model, shows you how to audit what's actually running, and gives you a hardening checklist to close the holes that let attackers in.

The Threat Model: Why VPS High CPU Is Often an Attack

A traffic spike might push your application CPU to 60% for a few minutes. But sustained 90%+ usage across all cores? That's different.

Cryptocurrency miners are the most common culprit. Once an attacker gains shell access through weak SSH credentials or an outdated web application, they drop a mining binary into /tmp or /dev/shm and configure it to start on boot. The miner connects to a remote pool and uses every available CPU cycle. Your VPS becomes their mining rig.

Botnet agents are another frequent cause. The compromised server sends spam, participates in DDoS attacks, or brute-forces other systems. Mail relay abuse specifically burns CPU because each outbound connection spawns processes for SMTP handshakes and content filtering.

The attack surface includes SSH brute-force (still effective against default port 22 with password auth), outdated CMS plugins, weak database passwords exposed to the internet, and application code that allows command injection. Once inside, the attacker often installs persistence mechanisms in cron jobs or systemd services so a simple reboot doesn't help.

Audit Checklist: Identify What's Consuming CPU

Before you can fix high CPU, you need to know what's causing it. Start with the running process list.

Run top or htop and sort by CPU usage. Note the process names, PIDs, and the user accounts they run under. A legitimate web server process will show httpd, nginx, or php-fpm. A miner often has a random alphanumeric name or disguises itself as a system process like systemd or kworker—but the CPU column gives it away.

Check the full process tree with ps auxf. This shows parent-child relationships. If you see a suspicious binary launched by cron or a user's shell, that's a red flag.

Search common hiding spots. Attackers drop binaries in /tmp, /var/tmp, /dev/shm, and sometimes in user home directories under hidden folders. Run ls -la /tmp /var/tmp /dev/shm and look for executables. Use file /path/to/binary to confirm it's an ELF executable rather than a script.

  • grep -r 'stratum+tcp' /tmp /var/tmp /dev/shm — miners connect to pool servers using this protocol
  • lsof -i — lists all network connections; check for unfamiliar remote IPs
  • netstat -tulpn — shows listening ports and the processes bound to them
  • crontab -l and check /etc/cron* — look for jobs that run unfamiliar scripts
  • systemctl list-timers — systemd timers can replace cron for persistence

Immediate Response: Stop the Malicious Process

Once you identify a suspicious process, kill it immediately. Use kill -9 PID to terminate it. But killing the process isn't enough—you need to remove the binary and any persistence mechanism.

Delete the executable with rm -f /path/to/binary. Check the user's crontab with crontab -u username -l and remove any unauthorized entries with crontab -u username -e. Review systemd services and timers; disable malicious ones with systemctl disable service-name and remove the unit files from /etc/systemd/system.

If the compromised account is a regular user, reset the password immediately or disable the account with passwd -l username. If it's root or a service account, you have a bigger problem. Consider whether the server needs to be rebuilt from a clean snapshot.

Before rebooting, verify that the malicious binary won't restart. Check /etc/rc.local, systemd services, init scripts in /etc/init.d, and hidden files in user home directories like .bashrc or .profile that might relaunch the attacker's code.

Security Hardening Steps to Prevent Future Attacks

Stopping the current attack is step one. Step two is closing the hole they came through.

SSH is the most common entry point. Edit /etc/ssh/sshd_config and set PasswordAuthentication no, PermitRootLogin no, and change the default port to something non-standard like 2200. Restart the SSH service with systemctl restart sshd. Make sure you test SSH access with your key before closing your current session—getting locked out is worse than high CPU.

Install fail2ban to automatically block repeated login failures. The default config watches SSH, but you can add jails for HTTP authentication, FTP, and mail services. Run fail2ban-client status to see active jails and blocked IPs.

Close unused ports. List open ports with netstat -tulpn and close anything you don't need. Use ufw (Uncomplicated Firewall) on Ubuntu or firewalld on CentOS. Allow only SSH, HTTP, and HTTPS unless you have specific requirements. For example: ufw allow 2200/tcp, ufw allow 80/tcp, ufw allow 443/tcp, then ufw enable.

Disable or remove unused services. If you're not running a mail server, stop and disable Postfix or Exim. If you don't need FTP, remove vsftpd. Every running service is a potential target.

Advanced Hardening: File Integrity and Process Monitoring

Basic hardening stops most attacks. Advanced monitoring catches the rest.

Install AIDE (Advanced Intrusion Detection Environment) or Tripwire to monitor critical files. AIDE creates a database of file checksums and alerts you when system binaries, configuration files, or other watched paths change. Initialize the database with aideinit, then run daily checks with a cron job. When AIDE reports changes, you'll know something modified /usr/bin, /etc, or other protected directories.

Enable process accounting with the psacct package. This logs every command executed on the system to /var/account/pacct. Use lastcomm to review the command history and identify unauthorized activity even after the process exits. In one case, process accounting revealed a miner that ran for 30 seconds every hour—short enough to evade manual checks but enough to drain CPU over time.

Set up resource limits with cgroups or systemd slices. This won't stop an attack, but it can contain the damage. For example, limit a web application user to 50% CPU so a compromised process can't consume the entire system.

Consider a host-based intrusion detection system like OSSEC. It combines log analysis, file integrity monitoring, and rootkit detection. The learning curve is steeper than fail2ban or AIDE, but the visibility is worth it for production servers.

Application-Level CPU Issues vs Security Issues

Not all high CPU is malicious. Sometimes it's just bad code.

Database queries without indexes can pin CPU for seconds or minutes. Use EXPLAIN on slow queries and add indexes where needed. Connection pooling misconfigurations cause similar symptoms—hundreds of idle connections each holding a tiny bit of memory and CPU.

Poorly written loops in application code, especially in PHP or Python scripts handling large datasets, will burn CPU. Profile the application with tools like Xdebug or py-spy to find hot spots.

Check your web server logs for unusual request patterns. A bot hammering a search endpoint or a crawler ignoring robots.txt can generate enough load to saturate CPU. Rate limiting with nginx limit_req or Apache mod_ratelimit helps here.

The difference between application load and a security issue comes down to user accounts. If the high CPU process runs as www-data or a known service account and connects only to your database, it's probably legitimate load. If it runs as a user account you don't recognize, connects to external IPs, and the binary sits in /tmp, that's an attack.

Verification: Confirm the Fix Holds

Killing the process and hardening SSH isn't enough. You need to verify the attacker is gone and can't return.

Monitor CPU usage for 48 hours. Use uptime to check load averages and top to watch process behavior. If CPU stays normal, the immediate threat is contained.

Check network connections daily with netstat -tulpn and lsof -i for the first week. New outbound connections to unfamiliar IPs could indicate a secondary payload or a re-compromise.

Review logs. Check /var/log/auth.log or /var/log/secure for new login attempts. fail2ban logs show blocked IPs in /var/log/fail2ban.log. If you see continued brute-force attempts, your SSH port is still discoverable—consider moving it again or restricting access by IP.

Run a rootkit scanner like rkhunter or chkrootkit weekly. These tools check for known rootkit signatures and suspicious system modifications. They're not foolproof, but they catch common post-exploitation tools.

If CPU spikes return or you find new suspicious processes, rebuild the server from a clean snapshot. Persistent re-compromise means the attacker installed a rootkit or backdoor you haven't found, and cleaning it manually is harder than starting fresh.

Long-Term Operational Security for VPS Environments

Fixing one attack doesn't mean you're done. Operational security is a practice, not a one-time task.

Patch your server monthly at minimum. Subscribe to security mailing lists for your distribution (ubuntu-security-announce, centos-announce) and apply updates promptly. Unpatched vulnerabilities in OpenSSH, sudo, or the kernel give attackers easy entry.

Rotate SSH keys and passwords on a schedule. If a team member leaves or a key is potentially compromised, revoke it immediately and regenerate authorized_keys files.

Implement centralized logging if you manage multiple VPS instances. Forward logs to a remote syslog server or a service like Papertrail so an attacker can't erase evidence by deleting local logs.

Test your backup and restore process. High CPU from a compromise is recoverable if you have clean snapshots. Schedule automated snapshots through your hosting provider and verify you can restore from them. A backup you've never tested is a backup you don't have.

Quick troubleshooting checklist

  • Take a snapshot or backup before making any configuration changes
  • Run top and ps auxf to identify the processes consuming CPU
  • Check /var/log/auth.log and /var/log/secure for failed login attempts
  • Scan for cryptocurrency miners using grep -r 'stratum+tcp' /tmp /var/tmp /dev/shm
  • Review cron jobs in /etc/cron* and user crontabs for unauthorized tasks
  • Disable password authentication in /etc/ssh/sshd_config and use SSH keys only
  • Close unused ports with ufw or iptables and verify with netstat -tulpn
  • Install and configure fail2ban to block brute-force attempts
  • Enable process accounting with psacct to track command execution history
  • Set up AIDE or Tripwire for file integrity monitoring on critical directories
  • Monitor CPU usage for 48 hours after changes to confirm stability

FAQ

What causes VPS high CPU in most cases?

High CPU on a VPS is typically caused by compromised user accounts running cryptocurrency miners, botnet scripts, or mail relay abuse. Legitimate causes include poorly optimized database queries, runaway application processes, or sudden traffic spikes. Check running processes first with top or htop to identify the specific binary consuming resources before assuming it's a traffic issue.

How do I find hidden malicious processes causing high CPU?

Use ps auxf to see the full process tree, check /tmp, /var/tmp, and /dev/shm for suspicious binaries, and run lsof -i to list all network connections. Miners often connect to stratum+tcp pools, so grep your process list and network connections for that string. Also check systemd timers with systemctl list-timers and review all cron jobs in /etc/cron* and user crontabs.

What SSH hardening steps prevent future high CPU attacks?

Disable password authentication and root login in /etc/ssh/sshd_config, use SSH keys only, change the default port, and install fail2ban to automatically block repeated failed login attempts. Limit SSH access by IP if possible using iptables or cloud firewall rules. These steps block the brute-force attacks that commonly lead to account compromise and CPU-draining malware.