Upgrade PVE 8 to PVE 9

Utilities~20 minView script

Performs the Proxmox VE 8 to 9 major-version upgrade following the official Proxmox procedure (Debian Bookworm to Trixie + PVE 8 to 9). Three upgrade approaches available — Automatic, Interactive, or Manual step-by-step — plus a stand-alone Pre-check to verify readiness without committing to the upgrade. Refuses to run from the web terminal because losing the connection mid-upgrade leaves the host in a broken state.

A major-version upgrade is destructive and not reversible

This operation rewrites the Debian base (Bookworm → Trixie) and the Proxmox stack in place. There is no rollback path. Before starting:
  • Verified backups of every VM and CT (PBS, vzdump, ZFS snapshots — and verify they restore).
  • Console / IPMI / iKVM access to the host for when SSH drops mid-upgrade.
  • The host already up-to-date on PVE 8.4.x (the script enforces this).
  • Ceph (if present) on version 19.x Squid.
  • At least 5 GB free on the root filesystem.

The mode menu

Launching the option opens a 4-way menu. The first three are different ways to perform the upgrade (pick the one that matches your comfort level); the fourth is a diagnostic that verifies the host is ready without changing anything:

PVE 8 to 9 upgrade mode menu with Automatic, Interactive, Pre-check and Manual guide options

Three ways to upgrade

Same end state, different level of operator involvement. None of them lets you skip the pre-flight safeguards or the post-upgrade verification — the difference is purely how the dpkg prompts during dist-upgrade are handled and whether you watch each step or hand it all off.

Plus a separate Pre-check

Option 3 of the menu — Run PVE 8 to 9 check — is not an upgrade mode. It runs Proxmox's official pve8to9 --full and offers guided remediation for the common blocking issues, then stops. Use it before committing to any of the three upgrade modes above. It also runs automatically as part of every upgrade flow, so this stand-alone option is for early verification or for re-running after manual fixes.

Why the web terminal is blocked

All three upgrade modes detect termproxy / vncshell in the parent process chain and refuse to run. Reason: the Proxmox web terminal is served by pveproxy, which is one of the services that gets upgraded mid-flow. As soon as pveproxy restarts, your terminal session dies — and so does the upgrade script that was running inside it. The host is left half-upgraded, no good way to resume.

Use SSH or physical / IPMI / iKVM console

SSH is the most common choice. Open it inside tmux or screen so the upgrade survives a brief network blip. The very first thing the script does is print the tmux/screen reminder if it detects you're in a plain SSH shell.

Automatic / Unattended mode

The fully unattended path. Every dpkg prompt is auto-answered with safe defaults so the upgrade runs end-to-end without operator input. Use it on vanilla installs where you haven't hand-edited config files, or when you're running the upgrade as part of a maintenance window and just want it to finish.

Auto-mode-specific behaviour

SettingEffect
ASSUME_YES=1Internal flag — every yes/no confirmation in the script auto-confirms
DEBIAN_FRONTEND=noninteractiveapt / dpkg run without opening any debconf prompt
--force-confdefFor untouched config files: install the maintainer's new version
--force-confoldFor files you customised: keep your version — never overwrite

Auto-mode flow

Six sequential phases. Any failure in phases 1-4 aborts cleanly and the host stays on PVE 8 — nothing has been written yet. Phase 5 (dist-upgrade) is the point of no return.

┌─────────────────────────────────────────────────────────────────┐
│  1. PRE-FLIGHT CHECKS                              (read-only)  │
│─────────────────────────────────────────────────────────────────│
│  • Block if running from web terminal (termproxy / vncshell)    │
│  • Abort if host already on PVE 9.x                             │
│  • Verify ≥ 1024 MB free in /var/cache/apt/archives             │
│  • Ping download.proxmox.com                                    │
│  • If Ceph is installed: must already be on 19.x Squid          │
│  • Run pve8to9 --full → no FAILs (offer guided repair if any)   │
└────────────────────────────────┬────────────────────────────────┘
                                 │  all pass
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│  2. BRING PVE 8 TO LATEST 8.4.x                                 │
│─────────────────────────────────────────────────────────────────│
│  • Delegate to scripts/global/update-pve8.sh                    │
│  • Final apt update + dist-upgrade on the 8.x branch            │
│  • Ensures the documented upgrade prerequisites are met         │
└────────────────────────────────┬────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│  3. REPOSITORY MIGRATION                                        │
│─────────────────────────────────────────────────────────────────│
│  • sed 's/bookworm/trixie/g' on /etc/apt/sources.list           │
│    and any /etc/apt/sources.list.d/*.list                       │
│  • Write deb822 .sources files for Proxmox + Debian + Ceph      │
│  • Try Enterprise repo → fall back to no-subscription on 401    │
│  • Comment out legacy .list files (do not delete yet)           │
│  • apt-get update with retry logic                              │
└────────────────────────────────┬────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│  4. VALIDATE BEFORE WRITING ANYTHING                            │
│─────────────────────────────────────────────────────────────────│
│  • apt-cache policy proxmox-ve  →  candidate must be 9.x        │
│  • apt-get -s dist-upgrade  (dry-run)                           │
│       →  must NOT propose removing proxmox-ve                   │
│  • Both must pass; otherwise abort with a clear message         │
└────────────────────────────────┬────────────────────────────────┘
                                 │  point of no return
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│  5. RUN dist-upgrade  (UNATTENDED)                              │
│─────────────────────────────────────────────────────────────────│
│  apt-get -y \\                                                   │
│      -o Dpkg::Options::='--force-confdef' \\                     │
│      -o Dpkg::Options::='--force-confold' \\                     │
│      dist-upgrade                                               │
│                                                                 │
│  • Full Bookworm → Trixie + PVE 8 → 9                           │
│  • Output streams in real time                                  │
│  • Also tee'd to /var/log/pve8-a-pve9-'<'timestamp'>'.log           │
└────────────────────────────────┬────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│  6. POST-UPGRADE                                                │
│─────────────────────────────────────────────────────────────────│
│  • EFI hosts:  apt install grub-efi-amd64                       │
│  • systemctl restart pve-manager                                │
│  • Re-run pve8to9 --full  →  confirm clean                      │
│  • Reboot prompt  (decline only if you have a reason)           │
└─────────────────────────────────────────────────────────────────┘

Pre-flight: what gets checked

CheckWhy it matters
Web terminal blockPrevents the upgrade from killing the shell that runs it
Already on 9.xAborts if the host already runs PVE 9 (nothing to do)
Latest PVE 8.4.xBrings PVE 8 to its final patch level via the PVE 8 update worker first; an old 8.x has different upgrade prerequisites
pve8to9 --fullProxmox's own upgrade-readiness check; FAILs block the upgrade until repaired
Disk space≥ 1024 MB free in /var/cache/apt/archives (downloaded .deb files)
ConnectivityPing to download.proxmox.com — if down, no point starting
Ceph 19.x SquidIf Ceph is installed, must already be on 19.x. PVE 9 cannot run with Ceph 17/18. Override flags exist (--ignore-ceph-check, --warn-ceph-check) but use them only if you know what you're doing

The dist-upgrade command (auto mode)

apt-get -y \
    -o Dpkg::Options::='--force-confdef' \
    -o Dpkg::Options::='--force-confold' \
    dist-upgrade

Output streams to stdout in real time and is also tee'd to /var/log/pve8-a-pve9-&lt;timestamp&gt;.log. You see everything — only the prompts are suppressed.

Post-upgrade tasks (auto mode)

  1. EFI hosts: installs grub-efi-amd64 (known issue per Proxmox docs — the upgrade doesn't pull it in automatically and the next boot would fail without it).
  2. Restart pve-manager. Forces a clean reload of the new daemons.
  3. Re-run pve8to9 --full. Surfaces any residual issues that the upgrade didn't resolve. If FAILs are reported, the same guided-repair menu as the pre-check appears.
  4. Reboot prompt. "It is RECOMMENDED to reboot now to load the new kernel and services. Reboot now?" Decline only if you have a specific reason — running on the old kernel after a major upgrade is risky.

Interactive mode

Same overall flow as the automatic mode — same pre-flight checks, same repository migration, same post-upgrade verification. The only difference is in the dist-upgrade step: you answer every dpkg config-file conflict prompt yourself. ProxMenux passes the upgrade through to plain apt-get dist-upgrade without the --force-conf* flags.

The dist-upgrade command (interactive mode)

apt-get dist-upgrade
# (user answers each dpkg config-file conflict prompt as it appears)

When interactive is the right choice

  • You've customised /etc/lvm/lvm.conf, /etc/ssh/sshd_config, /etc/default/grub or any other config file that gets touched by the upgrade.
  • You want to see exactly which packages introduce config conflicts and decide on a per-file basis.
  • You're upgrading a production host where any hidden change is unacceptable.

What to answer at each prompt

The same recommended-answers table that the manual procedure uses applies here too — see the Recommended answers for the dpkg prompts section in the manual procedure below. At any prompt, type D to see the diff before deciding, or Z to drop into a shell.

Manual upgrade procedure

This is what the Manual upgrade guide menu option displays — a faithful mirror of the official Proxmox 8-to-9 upgrade wiki organised in 4 phases. The script shows these commands; you type them yourself in a separate root shell. No automation — full visibility.

All commands need root

Run as root or prefix every command with sudo. The Proxmox host itself runs as root by default; only relevant if you locked it down.

Phase 1 — Preparation

Bring the host to the latest PVE 8.4.x, verify the version, validate Ceph (if used), run Proxmox's own pre-check, and start a terminal multiplexer to survive disconnections.

# Step 1 — Update PVE 8 to the latest 8.4+
apt update && apt dist-upgrade -y

# Step 2 — Verify version (must be 8.4.1 or newer)
pveversion

# Step 2.1 — Hyper-converged Ceph: must already be on 19.x Squid
ceph --version
# If older, follow https://pve.proxmox.com/wiki/Ceph_Squid

# Step 3 — Run the official upgrade-readiness check
pve8to9 --full
# If it warns about systemd-boot meta-package, remove it:
#   apt remove systemd-boot

# Step 4 — Start tmux or screen (so SSH disconnect doesn't kill the upgrade)
tmux new-session -s upgrade
# or
screen -S upgrade

Phase 2 — Repository migration

Switch every Debian and Proxmox repository from the Bookworm codename to Trixie, and convert the Proxmox sources to the new deb822 format. Pick step 7 OR step 8 depending on whether you have an Enterprise subscription. Skip step 9 if you don't run Ceph.

# Step 5 — Debian: bookworm → trixie
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list

# Step 6 — Same for the legacy enterprise list (only if you use enterprise)
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list.d/pve-enterprise.list

# Step 7 — Add the new PVE 9 enterprise repo (deb822) — Enterprise users only
cat > /etc/apt/sources.list.d/pve-enterprise.sources << EOF
Types: deb
URIs: https://enterprise.proxmox.com/debian/pve
Suites: trixie
Components: pve-enterprise
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF

# Step 8 — OR add the no-subscription repo (most home / lab users)
cat > /etc/apt/sources.list.d/proxmox.sources << EOF
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF

# Step 8.1 — Refresh and verify proxmox-ve candidate is 9.x
apt update && apt policy | sed -n '1,120p'

# Step 9 — Update Ceph repo (only if you run Ceph)
cat > /etc/apt/sources.list.d/ceph.sources << EOF
Types: deb
URIs: http://download.proxmox.com/debian/ceph-squid
Suites: trixie
Components: no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF

# Step 10 — Remove old .list files now superseded by deb822 .sources
rm -f /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/sources.list.d/ceph.list

# Step 11 — Final apt update
apt update

Phase 3 — The dist-upgrade

The actual upgrade. Step 12 is optional but recommended (silences a torrent of audit messages during the upgrade). Step 13 is the long one — answer every dpkg prompt using the table below. Step 13.1 is EFI-only and per the official known issues.

# Step 12 — Disable kernel audit messages (optional)
systemctl disable --now systemd-journald-audit.socket

# Step 13 — The main upgrade (this takes a while)
apt dist-upgrade
# (answer prompts using the table below)

# Step 13.1 — EFI hosts: install grub for EFI (per known issues)
[ -d /sys/firmware/efi ] && apt install grub-efi-amd64

Recommended answers for the dpkg prompts

These are the answers the official Proxmox guide recommends. Y = install maintainer's new version (overwrites your file); N = keep your current file. Always check the diff first when in doubt:

File / promptRecommended answerWhy
/etc/issueN (keep current)Banner you're used to seeing
/etc/lvm/lvm.confY (maintainer)PVE 9 needs the new LVM defaults
/etc/ssh/sshd_configY (maintainer)Re-apply your customisations after
/etc/default/grubN if customisedBoot params (IOMMU, PCI passthrough) live here
/etc/chrony/chrony.confY (maintainer)Time sync defaults updated for Trixie
Service restarts during upgradeYes (default)Avoids reboot for most services
apt-listchangesPress qJust exits the pager — info shown is the changelog summary

Inspecting a specific dpkg conflict

At any prompt, type D to see the diff between your current file and the maintainer's version, or Z to drop into a shell and decide later. Both of those are always safer than guessing.

Phase 4 — Post-upgrade

Verify the upgrade landed cleanly, reboot to load the PVE 9 kernel, confirm the new version, and (optional) modernise the few remaining legacy .list files into deb822.

# Step 14 — Re-run the readiness check (should be much cleaner now)
pve8to9 --full

# Step 15 — Reboot to load the new kernel and PVE 9 daemons
reboot

# Step 16 — After reboot, confirm PVE 9.x
pveversion
# Should show pve-manager/9.x.x

# Step 17 — Optional: modernise the remaining legacy .list files to deb822
apt modernize-sources
# (keeps .list backups as .bak)

Cluster & Ceph

Cluster: upgrade nodes one at a time

Detected via pvecm status. Do not upgrade more than one node at a time. Migrate guests off the node first, upgrade, reboot, verify the node is back in the cluster as PVE 9, only then move to the next node. Mixed PVE 8 / PVE 9 cluster works for the duration of the upgrade window, but live migration between mixed versions is not supported — only cold migration. HA groups will be migrated to the new HA rules format automatically.

Ceph: upgrade Ceph FIRST, then Proxmox

Ceph must already be on 19.x Squid before the Proxmox upgrade. The official order: Ceph 17/18 → Ceph 19 (per pveceph upgrade per node) → reboot for new Ceph daemons → Proxmox upgrade per node. Skipping the Ceph step leaves the cluster broken until you fix it from the console. Full Ceph procedure: Ceph Squid upgrade wiki.

Troubleshooting

Script aborts: "This script cannot be executed from the Proxmox web terminal"

Open SSH (or use console / IPMI / iKVM) and re-run from there. tmux new -s pveupgrade first if you want to survive a brief network drop.

pve8to9 reports FAIL and auto-repair Option 1 produces "command not found"

Known bug — the auto-repair refers to a function (configure_repositories) that doesn't exist in the current codebase. Use Option 2 (show manual commands) and run them from a separate shell, or run the canonical fixes by hand: apt-get update, then re-run the upgrade.

apt simulation flags "proxmox-ve will be REMOVED"

The new repos aren't reachable or the codename substitution didn't take effect. Check cat /etc/apt/sources.list.d/proxmox.sources — the Suites: line must say trixie, not bookworm. Also confirm apt-cache policy proxmox-ve shows a 9.x candidate from the new repo.

dist-upgrade fails partway through

Run apt-get -f install to resolve broken dependencies, then re-run the upgrade. If that fails, check the log at /var/log/pve8-a-pve9-&lt;timestamp&gt;.log — the last lines usually pinpoint the offending package. Do not reboot until dpkg -l | grep ^iU returns empty (no half-installed packages).

EFI host won't boot after reboot

The post-upgrade grub-efi-amd64 install handles this. If you skipped that step or it failed, boot from the Proxmox installer ISO in rescue mode, mount the root, chroot, and apt-get install grub-efi-amd64 &amp;&amp; update-grub.

GUI does not load after upgrade

systemctl status pveproxy and systemctl restart pveproxy. If still broken, check journalctl -u pveproxy -b for the actual error.

Network does not work after reboot

Check /etc/network/interfaces still references existing devices and ifupdown2 is installed: apt install ifupdown2. If interface names changed, see Persistent interface names.

Cluster split-brain after upgrading one node

Mixed PVE 8 / PVE 9 cluster is supported during the upgrade window but migration is cold-only. If the cluster shows the upgraded node as offline, check corosync on both: the QDevice / network config might have shifted. Run pvecm status on each node to confirm quorum.

Files involved

scripts/utilities/upgrade_pve8_to_pve9.sh                         # main upgrade orchestrator
scripts/utilities/pve8to9_check.sh                                # pre-check (separate menu option)
scripts/utilities/proxmox-upgrade-pve8-to-pve9-manual-guide.sh    # 17-step runbook
scripts/global/update-pve8.sh                                     # PVE 8 worker (final patches)
/etc/apt/sources.list                                             # bookworm → trixie sed
/etc/apt/sources.list.d/proxmox.sources                           # created (deb822 PVE 9)
/etc/apt/sources.list.d/debian.sources                            # created (deb822 trixie)
/etc/apt/sources.list.d/ceph.sources                              # created if Ceph
/etc/apt/sources.list.d/*.list                                    # legacy files commented out / removed
/var/log/pve8-a-pve9-'<'timestamp'>'.log                              # full upgrade log

Official references

The script's manual procedure is a faithful mirror of these official sources. When in doubt during a real upgrade, follow the official wiki — ProxMenux helps you execute it, but the source of truth is Proxmox.

Video walkthrough

Prefer watching the upgrade run end-to-end before doing it yourself? This walkthrough demonstrates the ProxMenux upgrade flow in real time.

External video on YouTube. Plays in privacy-enhanced mode (no cookies until you press play).

Related