When you have to suspend a WooCommerce client: anatomy
A WooCommerce client burned 40-60% CPU on a shared cPanel box for 48 hours, unreachable. The decision tree, the suspension, and the conversation after.
Anatomy of a forced suspension on a shared cPanel server
The decision to take a paying client offline to protect fourteen other paying clients is the worst part of running a small hosting agency. There is no scripted version of it that feels good. The client did not consent. They are paying you. The server is yours, the other clients are yours, and the contract you signed with each of them implies a level of service that one runaway WooCommerce install is currently making impossible to deliver.
This post is the version of that decision we wish someone had
written down for us the first time we made it. The numbers are
from a real incident: one of our WooCommerce clients, anonymised
here as riftvc, generated between forty and sixty percent
sustained CPU on a shared cPanel box for forty-eight hours, did
not respond to three emails, one phone call and one SMS, and was
ultimately suspended at the WHM level. The fourteen other accounts
on that server had been seeing visible page load degradation for
most of that window.
What follows is the decision tree we use, the actions we take before the suspension, the suspension itself, and the conversation that always comes afterwards. None of it is comfortable. All of it is part of the job.
How we knew it had to happen
The investigation took about ten minutes once we had decided to
look. htop sorted by %CPU and grouped by user (press u,
then t for the tree view) makes the answer obvious within
seconds on most boxes. One user owns the top of the process list.
On this server it was riftvc with a dozen long-running PHP
processes, each at single-digit CPU but adding up to a sustained
forty percent of the box.
# top, filtered to a single cPanel user
top -c -u riftvc
# same idea, one-shot, sorted by CPU
ps -u riftvc -o pid,pcpu,pmem,etime,cmd --sort=-pcpu | head -20The pattern was a runaway WooCommerce scheduled task feeding a
search-spider crawl trap on filter URLs. The spider was hitting
the same set of parametrised URLs over and over; each request
was generating a fresh, uncached page; and a separate wp-cron
task was firing every minute trying to clean up the resulting
mess. We have written about the filter URL part of the problem
separately in
the WooCommerce filter URL crawler trap fix.
It is one of the most common causes of WooCommerce resource
abuse on shared hosting and worth reading before you decide a
client is at fault rather than poorly configured.
What made this case a suspension candidate, rather than a normal "we will fix this for you on Monday" case, was the communication silence. Three emails, one phone call, and an SMS across two working days went unanswered. We had no way to get the owner of that account to look at it, and the cost of waiting another day was being paid by fourteen other paying customers.
The decision tree we use
We have written this down so that nobody on the team has to re-derive it under pressure. The order matters.
- Is this affecting other clients? If only the misbehaving account is suffering, do not suspend. Keep trying to reach the client and offer to help.
- Is the client reachable? If yes, get explicit authorisation before suspending anything. Most clients will agree to a short suspension if you explain that their site is taking the server down.
- Have we exhausted alternatives? Per-user CPU limits,
per-user FPM pool worker caps, a temporary
mod_securityrule to throttle the offending URL pattern, isolation of the user to its own FPM pool with hard limits. These are cheaper than suspension and recover faster. - Have we documented the impact? Before you suspend, you need
a paper trail: a screenshot of
htop, apsdump, the timestamps of your communication attempts, and a brief written summary of the alternatives you tried.
If all four answers are yes, suspension is justified and defensible. If any one of them is no, you are not ready.
Pre-suspension actions
Once the decision tree is satisfied, the suspension itself takes about a minute. Everything around it takes much longer and is where most of the value is.
- Snapshot the account. Run a cPanel backup of just the user
before suspending. This protects you against the client's
inevitable "you lost my data" claim.
/scripts/pkgacct riftvcproduces a single tarball under/home/. - Get a second pair of eyes. Anyone else on the team agreeing in writing that suspension is justified gives you cover when the client asks why. We use a short Slack thread with the evidence pasted in and an explicit "agree to suspend" reply.
- Write the notification in advance. Email and SMS. Include the cause, the evidence (without overwhelming the recipient), the path forward, and the contact channel. Have it ready to send the moment the suspension goes through, not after the client notices.
- Set a calendar reminder to follow up in twenty-four hours. Suspensions that are forgotten about become small, persistent reputational injuries.
The suspension itself
Two equivalent paths. In WHM: Account Functions → Suspend an Account, pick the user, write a brief reason, submit. From the shell:
# the canonical WHM script
/scripts/suspendacct riftvc "resource abuse 2026-05-10; see ticket"This parks the site at a cPanel "Account Suspended" page,
preserves all data, stops the user's processes and cron jobs, and
is fully reversible with /scripts/unsuspendacct riftvc. It
does not delete the account, it does not lose data, and it does
not charge the client extra. Within ten seconds the CPU load on
the box drops back to its normal range. That part feels good. The
part that follows does not.
The conversation that always follows
In our experience the client calls within an hour. The cPanel suspended page is the first thing they or their developer see, and they call because they think the server is down. The opening of that conversation is the most important part of the entire incident.
Lead with facts, not with annoyance. "Your site has been suspended because it was generating between forty and sixty percent of the server's CPU and we tried to reach you three times over the last two days." Then offer options:
- Fix the resource issue together. This is billable work and we will reverse the suspension as soon as the fix is verified.
- Upgrade to a tier with hard per-user resource limits, if your business model offers tiers.
- Move to a dedicated server or a VPS if the workload genuinely needs that scale.
The boundary that matters: do not unsuspend until the cause is addressed. Unsuspending an unfixed account simply re-creates the incident, and now the client believes you will reverse the decision under pressure. That is a much harder pattern to break than the initial suspension.
When NOT to suspend
The decision tree above is for the case where one client is hurting everyone else and you cannot reach them. There are several adjacent cases that look similar but require the opposite response.
- A genuine traffic spike. WooCommerce on a Black Friday is not abuse, it is the moment your client most needs your help. Suspending instead of scaling is a relationship-ending mistake.
- A scheduled one-time backup or migration. Long-running resource use that has a defined endpoint and an informed owner is not an emergency.
- A client mid-upgrade. If they have just paid for a higher tier and are in the migration window, that is the worst possible time to suspend; you will collapse their trust in the upgrade as a solution.
- A responsive, engaged client. If they are answering and working on it, you have alternatives.
The phrase we use internally: "suspension is for unresponsive clients with broken systems, not for responsive clients with busy systems."
The architectural lesson
Shared hosting is not really shared in the way the marketing
implies. It is "noisy-neighbour with mitigation". Per-user FPM
pools, cgroup-based CPU caps, and LVE limits all help and we
recommend running all of them. None of them eliminates the
underlying truth that fourteen accounts on a four-core box are
sharing a finite resource and one badly behaved account can still
ruin the day for the other thirteen.
When a client's resource profile makes them a chronic noisy neighbour (not a one-off incident but a pattern across weeks) the right answer is not tighter limits, it is migration. Either to a higher tier with dedicated resources, or to a VPS that they can saturate without harming anyone else. We have a separate planned write-up on the four-command resource abuse audit that covers how we identify those chronic-pattern clients before they become an emergency.
How ServerGuard handles this
ServerGuard's use case for this scenario cuts across resource attribution and risk classification. The detection side is implemented today: SGuard tracks per-user CPU, memory, and FPM child utilisation over time and flags chronic outliers. When a single account drives sustained load on a shared server, the system raises an alert with the evidence already gathered: process list, ownership attribution, the windows of sustained high utilisation, and a comparison to that user's baseline.
ServerGuard does NOT suspend client accounts. This is a deliberate, permanent design boundary, not a limitation waiting to be removed. Suspending a paying client touches the contract, the commercial relationship, and judgement calls about prior communication that an automated system has no business making. The agent will gather the evidence and present the case; a human at the agency makes the call.
This is the clearest example we have of where the line sits between what the AI does and what humans do. The AI gathers evidence, attributes resource use, and recommends; humans decide, communicate, and act on anything that touches a customer relationship.
If you are running ten to fifty WooCommerce clients on a couple of cPanel boxes and you would rather be the one making the suspension decision than the one finding out a day late that you needed to, that is what we are building.
Related posts
- 8 min read
The corrupted WordPress db.php dropin nobody warned you of
The corrupted WordPress db.php dropin nobody warned you about The ticket reads "Error establishing a database connection". You SSH into the box. MySQL is up. works. The other twelve WordPress sites on the same server are loading fine. Only
- 15 min read
86 CPU spikes in 24 hours: a multi-cause cascade postmortem
86 CPU spikes in 24 hours: a multi-cause cascade postmortem The mailbox at 08:00 had 86 ChkServd CPU alerts from , all from the previous 24 hours. Not a single tidy outage with a single cause. A steady drip of "CPU at 95% for the last minut
- 6 min read
When the client changes DNS without telling you first
When the client changes DNS without telling you first The ticket arrives on a Friday afternoon. Three words: "website is down". No screenshot, no error, no context. You load the site in a private window. It loads fine. You ask a colleague o