Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk9 min

How to Limit CPU Usage on a Linux VPS (systemd, Docker and cgroups)

Use systemd CPUQuota for a service-wide hard ceiling, Docker --cpus for containers, CPUWeight for proportional sharing and AllowedCPUs for affinity. Learn the exact commands and how to verify throttling through cgroup v2.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most reliable way to cap a long-running service on a Linux VPS is to place a CPU quota at its service or container cgroup boundary. For a systemd service, use a drop-in with CPUQuota=; for Docker, use --cpus (or the equivalent period and quota flags). Use CPUWeight= when workloads should share CPU proportionally rather than obey a fixed ceiling, and use AllowedCPUs= or --cpuset-cpus when execution must be confined to selected CPUs.

CPU percentages in systemd are measured against one CPU, not the entire VPS. Thus, CPUQuota=20% permits one-fifth of one CPU, while CPUQuota=200% permits up to two CPUs’ worth of execution. The setting you choose must leave capacity for the kernel, SSH, monitoring, storage processes and any other services that need predictable latency.

As an Amazon Associate I earn from qualifying purchases.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the control boundary before changing a setting

First identify what is consuming CPU and how it is launched. A hard limit belongs at the boundary that owns the workload, otherwise child processes, restarts or parallel workers may escape the limit.

  • systemd service: Put the limit on the unit, so the service and processes it starts are governed together.
  • Docker container: Apply the limit to the container with Docker’s resource flags.
  • One-off command: Run it in a transient systemd scope when you need the restriction only for that invocation.
  • Several unrelated processes: Group them under a dedicated service, slice or cgroup before applying a quota.

Limiting an individual process with a shell utility or a per-process resource limit is a different operation. It may not cover descendants and can terminate a process after it accumulates a CPU-time limit. Service- and container-level controls are designed for ongoing workloads.

CPU quota, weight and CPU affinity are different controls

Control Purpose What happens under load Typical scope
CPUQuota= Hard ceiling on CPU time The cgroup is throttled after its configured bandwidth is consumed systemd unit or slice
--cpus or --cpu-quota Hard ceiling for a Docker container Container execution is throttled when its quota is exhausted Docker container
CPUWeight= or cpu.weight Proportional sharing Allocation changes relative to competing cgroups; there is no fixed percentage cap systemd unit or cgroup
AllowedCPUs= or --cpuset-cpus CPU placement (affinity) Tasks run only on the selected CPUs, but may still consume all available time there systemd unit or container

A quota and an affinity rule can be combined. For example, a workload can be restricted to CPUs 2 and 3 and also capped at 50% of one CPU. Affinity alone is not a percentage limit: a process pinned to one CPU can still use that CPU continuously.

Limit a systemd service with a persistent CPU quota

A drop-in file is safer than editing a vendor unit directly. It survives package upgrades and keeps your local change separate from the unit supplied by the distribution or application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Create the drop-in directory and file

Replace example.service with the real unit name. Create /etc/systemd/system/example.service.d/cpu.conf containing:

[Service]
CPUQuota=50%

This example allows the unit up to half of one CPU. If the service is multi-threaded and needs two full CPUs at peak, a value of 200% represents two CPUs’ worth of quota. The percentage is always expressed relative to one CPU, even on a VPS with multiple virtual CPUs.

2. Reload unit definitions and restart the service

  1. Run sudo systemctl daemon-reload so systemd reads the new drop-in.
  2. Apply it to a running service with sudo systemctl restart example.service.
  3. Check the unit with systemctl status example.service and confirm that it remains active.

A reload alone rereads configuration but does not necessarily move an already-running process into the new limit. Restarting the unit makes the change take effect for the service’s processes.

3. Confirm the effective quota

Inspect the value systemd is actually using:

systemctl show example.service -p CPUQuotaPerSecUSec

Then observe CPU use with the service status view and a monitoring tool such as top or htop. A busy process may still appear runnable, but its cgroup will be throttled once the quota’s bandwidth is used during a scheduling period. The observed percentage can fluctuate over short intervals; evaluate it over a period long enough to include the service’s normal workload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Leave operating headroom

Do not allocate the entire practical capacity of the VPS to one service. The kernel, login sessions, networking, storage, security agents and other units need CPU time. A quota that looks acceptable in a quiet test can make the host feel unresponsive when backups, log rotation or a deployment runs.

Use systemd weights when the goal is fair sharing

CPUWeight= changes the service’s relative priority among cgroups that compete for CPU. It is appropriate when a batch worker should yield to an API service but may use spare CPU when the API is idle. It is not a deterministic ceiling: if no other workload is competing, a low-weight service can still run on all available CPUs.

The cgroup v2 interface uses a default cpu.weight of 100. You can assign different weights to sibling services so the scheduler divides contested CPU proportionally. The related cpu.weight.nice interface uses the familiar nice range from -20 through 19. These controls affect fair-class scheduling preference; they do not provide the stop-at-a-number behavior of a CFS quota.

Use a quota when exceeding a limit would harm the VPS. Use a weight when the requirement is “prefer this service, but let it use idle capacity.” Many production setups use both: a moderate quota as a safety boundary and weights to decide which services receive the remaining time during contention.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Pin a systemd unit to selected CPUs

AllowedCPUs= restricts where a unit may run. It is useful for isolating latency-sensitive work from a CPU-intensive worker or for keeping a workload on a known set of virtual CPUs. Pinning does not reduce the amount of time the workload can consume on those CPUs.

Set it in the same drop-in when needed:

[Service]
CPUQuota=100%
AllowedCPUs=0-1

Here the service is confined to CPUs 0 and 1 and receives a quota equal to one CPU. Check the unit’s effective properties after reloading and restarting; a parent slice or another drop-in can impose additional restrictions.

Apply a temporary limit to a one-off command

For a command that should not receive a permanent unit file, use a transient systemd scope:

systemd-run --scope -p CPUQuota=50% command

Replace command with the executable and its arguments. The scope is created dynamically and normally disappears when the command exits. This requires a systemd environment that permits the caller to create the scope and delegate the required resource controller. In automation, record the transient unit name and verify its cgroup rather than assuming the option was accepted.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If the command launches children, a scope is preferable to a per-process limit because the children remain in the same cgroup while they are descendants of the scoped workload. Confirm the resulting unit with systemctl status or systemctl show before relying on it for a critical job.

Limit a Docker container

Docker’s convenient CPU control is the --cpus option:

docker run --cpus="0.5" image

Docker documents this as equivalent to a period of 100000 microseconds and a quota of 50000 microseconds:

docker run --cpu-period=100000 --cpu-quota=50000 image

The first form is easier to read; the explicit pair is useful when you need to understand or integrate with cgroup settings. A value of 0.5 permits half of one CPU on average over each quota period. It does not mean half of the VPS’s total CPU capacity.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Restrict the container to specific CPUs

Use --cpuset-cpus for placement:

docker run --cpus="1" --cpuset-cpus="0" image

This permits up to one CPU’s worth of time while allowing execution only on CPU 0. Without the quota, a container pinned to CPU 0 could consume that CPU continuously. As with systemd, combine affinity and quota only when both constraints are required.

Change or inspect a running container

For an existing container, Docker can update supported resource limits with docker update. Check the container’s configuration and runtime statistics after changing it, and make sure the command is applied to the container that actually owns the busy process. A process started directly on the host is not controlled by a Docker limit merely because it accesses the same files or network.

Verify limits through cgroup v2

On systems using the unified cgroup v2 hierarchy, the kernel exposes CPU controls as files in the workload’s cgroup. The important files are:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • cpu.max contains the quota and period. A quota value of max means no quota at that boundary; the second value is the period.
  • cpu.weight contains the proportional scheduling weight. Its documented default is 100.
  • cpu.stat reports usage and throttling counters for the cgroup.
  • cpu.stat.local reports throttling on the cgroup’s own run queues and can include throttling inherited from ancestor bandwidth limits.

To locate a systemd service’s cgroup, first display its control-group path:

systemctl show example.service -p ControlGroup

Use the returned path below /sys/fs/cgroup, then read the files:

cat /sys/fs/cgroup/<control-group-path>/cpu.max
cat /sys/fs/cgroup/<control-group-path>/cpu.weight
cat /sys/fs/cgroup/<control-group-path>/cpu.stat
cat /sys/fs/cgroup/<control-group-path>/cpu.stat.local

The placeholder path in the command must be replaced with the actual path printed by systemd. Do not copy the angle brackets literally.

Interpret throttling counters

In cpu.stat, counters such as the number of throttled periods and throttled microseconds show whether the workload is repeatedly hitting its quota. A rising throttling count with sustained CPU demand indicates that the ceiling is active. If cpu.stat.local shows throttling while the local quota appears generous, inspect parent slices and ancestor cgroups: an upper-level bandwidth limit can throttle descendants.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why a configured limit may not behave as expected

The drop-in was not loaded

Run sudo systemctl daemon-reload, restart the unit, and query CPUQuotaPerSecUSec. If the value is missing or different, inspect all drop-ins and the unit’s parent slice. A later fragment or a parent resource-control setting can override or constrain the value you edited.

The wrong process was limited

Confirm the process belongs to the unit or container you changed. Services may spawn helper processes, workers or separate units. Docker commands affect the named container, not similarly named host processes.

The quota is correct but CPU still looks high

Short sampling windows can make usage appear above or below the configured average. Check the cgroup’s quota and throttling counters over time. Also remember that a quota of 200% legitimately permits two CPUs’ worth of execution, and that percentages are not a share of the entire VPS.

A parent cgroup or VPS policy is the real bottleneck

Guest-level cgroups are nested. A service can be below its own quota while an ancestor slice or the VPS provider’s host-level policy limits the whole virtual machine. Compare the service’s cpu.max with parent settings and inspect cpu.stat and cpu.stat.local. If the guest configuration is permissive but all workloads are constrained, the provider’s allocation or host policy may be the limiting layer; only the provider can change that.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Nice changed responsiveness but did not cap CPU

nice and cpu.weight.nice alter scheduler preference for fair-class processes. They do not impose a deterministic ceiling. Replace them with a service-level quota when the requirement is “never exceed this amount,” or keep them as a secondary preference when workloads merely need to yield during contention.

LimitCPU= was used for a service-wide problem

Per-process CPU limits are accounted independently and can behave differently after forks. They are not a substitute for a unit-level resource control when a service consists of multiple cooperating processes. Put the limit on the service cgroup instead.

Operational checklist for a VPS

  1. Identify the owner of the workload: systemd unit, Docker container, transient command or a group you can place in a cgroup.
  2. Decide whether you need a hard ceiling, proportional sharing or CPU placement.
  3. Choose a value relative to one CPU and reserve capacity for the operating system and latency-sensitive services.
  4. Apply the setting at the service or container boundary, not only to the current worker process.
  5. Reload and restart when systemd configuration requires it; for Docker, verify the updated container settings.
  6. Read the effective property or cgroup files rather than trusting the configuration file alone.
  7. Watch usage and throttling counters during the workload’s real peak period.
  8. If behavior is inconsistent, inspect parent cgroups and remember that the VPS host can impose an additional limit.

This sequence separates three decisions that are often confused: how much CPU a workload may consume, how it competes with neighbors, and where it is allowed to run. Keeping those decisions explicit makes CPU control predictable without starving the rest of the VPS.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.