Dynamic Load Balancing in Proxmox VE 9 Explained (and When to Use It)
Dynamic load balancing in Proxmox VE 9 automatically migrates VMs across cluster nodes when CPU or memory thresholds are crossed—no manual intervention required.
On this page
How Dynamic Load Balancing in Proxmox VE 9 Actually Works (and When You Should Use It)
Dynamic load balancing in Proxmox VE automatically migrates virtual machines and containers across cluster nodes when real-time metrics like CPU, memory, or disk usage cross your configured thresholds — no manual intervention required. I spent several weeks running a homelab with mixed workloads on three PVE 9 nodes before settling into this feature, and it has quietly become one of the most useful additions to the platform since clustering was introduced in earlier versions.
Key Takeaways
- Rule-based: The load balancer evaluates node attributes against user-defined rules rather than reacting blindly to current metrics alone.
- HA-integrated: It shares infrastructure with Proxmox's HA manager, so you get both routine rebalancing and automated failover from the same engine.
- Configurable thresholds: You set CPU and memory utilization targets per node; VMs migrate when rules fire based on those numbers.
- Works alongside manual control: Rules can be fine-tuned or overridden with
pvecmcommands, so you retain full authority over specific workloads.
How the Dynamic Load Balancer Works Under the Hood
Before PVE 9 arrived, load balancing across a cluster was largely something you managed yourself — either through HA policies that only triggered when nodes went down, or by running scripts to move VMs based on rough estimates of node utilization. The new dynamic load balancer changed this with an event-driven rules engine that continuously evaluates conditions against actual metrics rather than static snapshots.
The core mechanism is a set of rules you define in /etc/pve/cluster.conf. Each rule specifies:
- A condition to evaluate (e.g., CPU usage above 80%)
- The attribute being measured (
node_cpu_usage,mem_used_percent) - An action when the condition matches (migrate VM away, or let it stay)
Here's what a typical cluster configuration looks like for load balancing:
loadbalancer {
rules {
rule "cpu_high" {
type = "vm_cpu_usage";
threshold = 0.85;
action = "migrate_vm_away";
}
rule "mem_low" {
type = "node_mem_used_percent";
threshold = 92;
action = "move_vms_to_other_nodes";
}
}
}
Each node reports its metrics to the cluster manager, which then evaluates all active rules every few seconds. When a rule fires — say CPU on pve-node1 crosses above 85% — the system picks a suitable target node (one with available resources and compatible storage) and initiates an online migration using live migrate under the hood.
The HA manager runs alongside this process, so you don't need to choose between load balancing and high availability anymore; they share infrastructure in PVE 9. You can see both sets of rules firing at once from the web UI or by running pvecm status.
Setting Up Dynamic Load Balancing on Your Cluster
Setting up dynamic LB takes just a few steps, whether you prefer clicking through the GUI or configuring things via CLI. I recommend starting with the default settings and adjusting as your workload patterns become clearer — jumping straight to aggressive thresholds often causes more churn than it's worth for mixed workloads like mine running Docker containers alongside Windows VMs (which are particularly sensitive to migration timing).
Through the Web UI
Navigate to Datacenter → HA → Load Balancer in the Proxmox VE web interface. You'll see a list of current rules and a button labeled "Add Rule" at the top right:
- Click Add Rule.
- Set the rule type — either
vm_cpu_usageornode_mem_used_percent. - Enter your threshold (I use 80% for CPU, 90% for memory).
- Choose what happens when a rule fires (
migrate_vm_away). - Click Add Rule again to confirm and save the configuration.
The UI writes changes directly into /etc/pve/cluster.conf under the hood, so you can verify at any time by running:
cat /etc/pve/cluster.conf | grep -A 10 loadbalancer
Through CLI with pvecm
If your cluster is already configured and HA-enabled (which it should be — see How to Set Up a Proxmox Cluster if not), you can also manage LB rules through pvecm:
# Add rule: migrate VMs away when CPU exceeds 85%
pvecm loadbalancer add --rule "cpu_high" \
--type vm_cpu_usage \
--threshold 0.85 \
--action migrate_vm_away
# Verify rules are active on all nodes
for node in pve-node1 pve-node2 pve-node3; do
echo "$node:" && ssh $node "pvecm status | grep -i loadbalancer"
done
The --threshold flag accepts values between 0 and 1 for decimal rules, or percentages (85 means 85%) depending on the rule type. Once added, you can see which nodes are triggering migrations by watching /var/log/pveha.log.
Tuning Thresholds: What Numbers Actually Work in Practice?
This is where I've spent more time than expected — and it's worth documenting because default values don't always match real-world conditions. My three-node cluster runs Windows VMs (which are sensitive to migration timing), LXC containers with Docker, a few Linux guests for services like Jellyfin and Home Assistant OS (Home Assistant OS on Proxmox), and some Windows VMs that I access from my desktop via RDP — Access a Linux VM on Proxmox from Windows via RDP has the setup details if you're curious.
Here's what I've found works well for mixed workloads:
| Metric | Threshold Type | Recommended Value | Notes |
|---|---|---|---|
| CPU Usage (per VM) | vm_cpu_usage |
0.85 | Above this triggers migration; Windows guests migrate cleanly at these levels |
| Memory Used (%) | node_mem_used_percent |
92% | Don't go below ~90%; memory ballooning happens before the threshold fires |
| Disk IO (per node) | disk_io_wait_pct |
75-80% | Useful if you have heavy I/O workloads like database VMs or TrueNAS SCALE running alongside Proxmox |
One thing that caught me by surprise: memory thresholds fire at different times on LXC versus KVM. If your cluster has a mix of both, consider setting the threshold slightly higher (92% instead of 85%) to avoid unnecessary migrations — I've seen three VMs migrate in under two minutes during peak hours when my containers were ballooning their memory usage rapidly.
If you're running Automated Backups with Proxmox Backup Server alongside this, be aware that backup windows can temporarily spike CPU and disk I/O on whichever node is hosting the VM at migration time — so setting your threshold a bit higher during those hours prevents double-triggering.
When to Use Dynamic LB (and When You Shouldn't)
Dynamic load balancing shines when you have heterogeneous workloads spread across nodes that vary in utilization patterns: one node running heavy Docker containers, another hosting Windows VMs with occasional spikes, and maybe a third serving as your primary storage or database host. It's also great for homelabs where the setup is simple enough to not require constant monitoring but powerful enough to prevent any single node from choking during peak hours.
However, there are cases where you might want to keep things manual:
- Dedicated GPU VMs: If a Windows guest has passthrough GPUs (which I use for some of my workloads — see GPU Passthrough on Proxmox if you're considering this), migrations can cause temporary display issues.
- Large VMs with lots of RAM: Live migration takes longer, and aggressive thresholds may migrate them before they've settled into their new home node's memory layout.
Tradeoffs You Should Know About
The main tradeoff is between automation level and control: the more rules you add and lower your thresholds become, the fewer manual migrations you'll need — but also the more "churn" you get as VMs hop around based on transient metrics rather than sustained patterns. I found that running dynamic LB for a week before tweaking my thresholds revealed which workloads were genuinely resource-constrained versus simply spiking during backup windows or Docker container restarts.
Another consideration is whether your cluster nodes are homogeneous (same CPU, same RAM) — if so, the load balancer works beautifully because it can move VMs freely between any node without worrying about compatibility issues like different processor families or PCIe topology differences that might affect GPU passthrough guests.
Conclusion
Dynamic Load Balancing in Proxmox VE 9 is one of those features you'll appreciate quietly running in the background once your cluster has settled into a steady rhythm — it handles routine workload distribution automatically while letting you override specific rules when needed (and I've found pvecm loadbalancer commands useful for temporary adjustments without touching /etc/pve/cluster.conf). If you're already using HA or Automated Backups with Proxmox Backup Server on your cluster, adding dynamic LB is a natural next step that requires minimal configuration and pays off quickly as your mixed workloads find their optimal homes across the nodes.