Proxmox VEXI · ClusteringCluster lifecycle
Joining, removing, and replacing nodes
What you'll learn
- Join a node to an existing cluster and verify the join rather than assume it
- Remove a node cleanly, in the order that preserves what you need
- Replace a permanently failed node, including recovering its guest configurations
- Explain why a removed node must be reinstalled before it is used again
Prerequisites
Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12
Why this matters in production
Adding a node is routine and forgiving. Removing one contains the irreversible steps, and the ordering matters more than the commands do: get it wrong and a node’s guest configurations are gone before you have finished reading the confirmation prompt.
Which command runs where
This is the first thing to get straight, because the two commands look similar and are not interchangeable.
| Command | Run on | Purpose |
|---|---|---|
pvecm create <name> | The first node | Creates the cluster |
pvecm add <cluster-node> | The joining node | Joins this node to an existing cluster |
pvecm addnode <node> | An existing cluster node | Internal — invoked by the join process, not by you |
pvecm delnode <node> | An existing cluster node, not the one being removed | Removes a node |
pvecm status / pvecm nodes | Any node | Read state |
pvecm qdevice setup / remove | An existing cluster node | QDevice lifecycle |
The pairing to remember: you add from the new node and you delete from an old one. Running either from the wrong place is where most of the confusion in this procedure comes from.
Before you join anything
set -euo pipefail
PEER=pve-01.example.com
PEER_IP=192.0.2.11
# 1. Same PVE version as the cluster. A version mismatch is not supported.
pveversion -v | head -3
# 2. Forward and reverse resolution agree, for this node and the peer.
hostname -f
getent hosts "$(hostname -f)"
getent hosts "$PEER"
getent hosts "$PEER_IP"
# 3. Time is synchronised. Corosync will not tolerate meaningful skew.
chronyc tracking | grep -E 'Reference ID|System time|Leap status'
# 4. Reachability on the ports that matter: SSH for the join itself,
# 8006 for the API, and the corosync range for cluster traffic.
nc -z -w3 "$PEER_IP" 22 && echo 'ssh ok'
nc -z -w3 "$PEER_IP" 8006 && echo 'api ok'
# 5. THIS NODE MUST BE EMPTY. Joining destroys its local configuration.
qm list
pct listJoining
The modern path is through the GUI: on an existing node, Datacenter → Cluster → Join Information, copy the blob, and paste it into Join Cluster on the new node. It carries the address, the fingerprint and the peer list, which removes the three things people mistype.
From the command line, on the new node:
set -euo pipefail
PEER_IP=192.0.2.11
# Run on the NEW node. It will ask for the root password of the peer.
# --fingerprint comes from the join information on the existing cluster.
pvecm add "$PEER_IP" \
--fingerprint 'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99'
# On a multi-link cluster, give this node an address on every link, or it
# joins with one link and the redundancy you think you have is incomplete.
# pvecm add "$PEER_IP" --link0 10.0.0.14 --link1 10.0.1.14
# --use_ssh forces the older SSH-based join path, which is the fallback when
# the API join fails.set -euo pipefail
# 1. The node is a member and the vote count has increased.
pvecm status | grep -E 'Quorate|Expected votes|Total votes'
pvecm nodes
# 2. Every link is up to every peer - not just link 0.
corosync-cfgtool -n
# 3. pmxcfs has synchronised: the new node can see the cluster's guests
# and storage, which it could not before.
cat /etc/pve/.members
pvesm status
# 4. A write from the new node reaches the cluster.
PROBE=/etc/pve/.join-probe
date -Is > "$PROBE" && cat "$PROBE" && rm -f "$PROBE"
# 5. Certificates are consistent. If the GUI on one node cannot proxy to
# another, this is usually why.
pvecm updatecertsRemoving a node
The order is the whole procedure. Three of these steps are hard to undo.
set -euo pipefail
DOOMED=pve-04
# --- On the node being removed ---
# 1. Move every guest off it. Nothing should be left running or configured.
# Migrate what can migrate; back up and rebuild what cannot.
qm list
pct list
# 2. Take it out of HA management, so the CRM stops trying to place work on it.
ha-manager status
# --- On a node that is staying ---
# 3. If a QDevice is configured, remove it FIRST. Removing a node with a
# QDevice in place is a documented way to end up unpicking state by hand.
pvecm status | grep -i qdevice && pvecm qdevice remove || true
# 4. Confirm the cluster is quorate and healthy before changing membership.
pvecm status
# 5. POWER THE DOOMED NODE OFF, and leave it off.
# It must not be running when it is removed.
# 6. Remove it. This is the irreversible step.
pvecm delnode "$DOOMED"
# 7. Verify: expected votes have dropped, the node is gone from the nodelist.
pvecm status
pvecm nodes
# 8. Its directory under /etc/pve may remain. Check it is empty of guest
# configurations BEFORE removing it - see the warning below.
ls -la "/etc/pve/nodes/$DOOMED/"Replacing a failed node
The sequence for a node that has died and is not returning:
- Confirm it is genuinely dead, through out-of-band management. A node that is partitioned rather than dead is a different problem entirely.
- Move its guest configurations to a surviving node, for every guest on shared storage. Do this first.
- Recover the rest from backup. Anything that was on local storage.
- Remove it:
pvecm delnode pve-04from a surviving node. - Tidy
/etc/pve/nodes/pve-04/once you have confirmed it holds nothing you need. - Build the replacement. A fresh install. The hostname may be reused or not — Proxmox supports either, and reusing it keeps documentation simpler at the cost of some ambiguity in old logs.
- Join it as a new node, and verify as above.
Common failure modes
The join fails
# pvecm add 192.0.2.11 --fingerprint AA:BB:...:99detected the following error(s):
* this host already contains virtual guests
Check if node may join a cluster failed!Illustrative output
| Symptom | Cause | Fix |
|---|---|---|
this host already contains virtual guests | The joining node is not empty | Back up and remove its guests, or rebuild it |
| Authentication failure | Wrong root password, or the fingerprint does not match | Re-copy the join information from the cluster |
cluster not ready - no quorum? | The cluster you are joining is not quorate | Fix the cluster first |
| Version mismatch errors | Different PVE versions | Bring both to the same version |
| The join succeeds and the node shows only link 0 | --link1 was omitted | Add the address to corosync.conf and reload |
| Time-related failures | Clock skew | Fix NTP on both, then retry |
After a join, quorum does not settle
Check that the addition actually took on every node — pvecm status on each
should show the same Config Version and the same expected votes. A node
that has not picked up the new corosync.conf will disagree, and the
disagreement is visible in that one line.
A break/fix exercise
A node joins successfully and the cluster silently loses its link redundancy
Symptoms
- pvecm add on the new node completed without error
- pvecm status shows the node as a member with the expected vote count
- The GUI shows all four nodes green and guests can be migrated to the new node
- corosync-cfgtool -n on an existing node shows the new node reachable on LINK 0 only
Available evidence
- The three original nodes each have ring0_addr and ring1_addr in corosync.conf
- The new node entry in the nodelist has ring0_addr only
- The join was performed with pvecm add and the peer IP, with no --link options
- The second corosync VLAN is trunked to the new node switch port and the interface is up
Show diagnosis & remediation
Root cause
pvecm add joins with the links it is given. With no --link options, the joining node received a single link derived from the address used to reach the peer, so its nodelist entry has ring0_addr and nothing else. Nothing about this produces an error, because a one-link node in a multi-link cluster is a valid configuration - it simply has no redundancy.
Safe remediation
Add the missing ring1_addr to the new node entry in /etc/pve/corosync.conf, increase config_version, and apply with corosync-cfgtool -R. Then confirm from an existing node that corosync-cfgtool -n reports the new node reachable on both LINK 0 and LINK 1. Prefer joining with explicit --link0 and --link1 arguments so this does not arise.
Verification
corosync-cfgtool -n on every node shows the new node connected on both links. Administratively downing the primary link interface on the new node in a maintenance window leaves it a member of the cluster, reachable over link 1, with pvecm status still quorate.
Prevention
Make explicit --link arguments part of the join procedure on any multi-link cluster, and add a post-join verification step that runs corosync-cfgtool -n from an existing node rather than from the one just joined. A node that joined with fewer links than the cluster uses produces no symptom at all until the day link 0 fails, which is precisely when the redundancy was supposed to matter.
Production considerations
Common mistakes
- Running
pvecm addon the wrong node. It runs on the joiner. - Joining a node that has guests on it, and losing its configuration.
- Joining without
--linkarguments on a multi-link cluster, silently ending up with one link. - Running
delnodebefore moving the guest configurations off. - Removing a node that is partitioned rather than dead.
- Powering a removed node back on without reinstalling it.
- Removing a node while a QDevice is still configured.
- Joining into a cluster that is already degraded.
Key takeaways
pvecm addruns on the joining node;pvecm delnoderuns on a node that is staying.pvecm addnodeis internal.- A joining node adopts the cluster’s configuration and loses its own. Join empty nodes.
- On a multi-link cluster, join with explicit
--linkarguments and verify withcorosync-cfgtool -n. - Move guest configurations off a dead node before
delnode, and be certain the node is off first. - Removal is one-way. A removed node must be reinstalled before it can rejoin.
- Removing a genuinely dead node promptly lowers the quorum threshold and restores failure tolerance.
Knowledge check
Knowledge check · 5 questions
Q1. An administrator wants to add a new node to an existing three-node cluster. Where is pvecm add executed?
Q2. Which of these must happen before running pvecm delnode on a node being decommissioned? Select all that apply.
Q3. A node removed from a cluster can be powered back on later and rejoined without being reinstalled.
Q4. A standalone Proxmox host running eight production guests needs to become part of an existing cluster. What is the supported approach?
Q5. A four-node cluster loses one node permanently. Why does removing it promptly with delnode improve resilience rather than merely tidying up?
Passing score: 75%. Answers are checked in this browser.