How to back up a server before an Ubuntu release upgrade
Before you run do-release-upgrade, take a cloud snapshot of the server, dump its databases and copy them and your important files off the machine, and record the installed packages, holds, repositories and running services so you can compare afterwards. A release upgrade can't be undone: if it breaks something you can't fix forward, restoring the snapshot is the way back.
Why release upgrades break servers
do-release-upgrade replaces almost every package with the next release's version. Most servers come through fine. The ones that don't usually fail for one of these reasons:
- Third-party repositories and PPAs are switched off. They stay listed, marked
Enabled: no, and what you installed from them stays at its old version. Ubuntu calls this the most common cause of upgrade issues. - Pending updates and holds. The upgrade won't start while any update is waiting, including one for a held package.
- Configuration file prompts. Where you and a package both changed a file, you pick a version. A wrong answer drops your settings or keeps a file the new version can't read.
- Version jumps. Languages and databases move to new major versions.
From 24.04 LTS to 26.04 LTS, these jumps matter most on a server:
| Software | 24.04 LTS | 26.04 LTS | What to watch |
|---|---|---|---|
| PHP | 8.3 | 8.5 | New FPM socket and a new /etc/php/8.5/ config folder |
| PostgreSQL | 16 | 18 | Your data stays in the 16 cluster until you upgrade it |
| MySQL | 8.0 | 8.4 | Accounts using mysql_native_password are locked out by default |
| MariaDB | 10.11 | 11.8 | New major version |
| Python | 3.12 | 3.14 | Virtual environments must be rebuilt |
| Redis | 7.0 | 8.0 | New major version |
| Linux kernel | 6.8 | 7.0 | Runs after the final reboot |
Dovecot 2.4 also changed its configuration format, and OpenSSH moves from 9.6 to 10.2. Read the 26.04 summary for LTS users for everything your server runs.
When you can upgrade
Ubuntu offers an upgrade from one LTS to the next only after the new release's first point release. Ubuntu 26.04.1 came out on 27 August 2026, and the upgrade from 24.04 is now offered. You can't skip an LTS: a 22.04 server goes to 24.04 first.
-c only checks: it prints the new version and exits 0, or prints No new release found. and exits 1:
do-release-upgrade -cPrompt in /etc/update-manager/release-upgrades sets what it looks for: lts, normal (interim releases too) or never. -d forces an LTS upgrade before the point release; Ubuntu advises against it in production.
Take a snapshot, and copies off the server
A snapshot captures the whole disk, so restoring it puts the server back exactly as it was. Take it last, right before the upgrade, with your provider's guide: DigitalOcean, Hetzner, Vultr, Linode, AWS EC2, Lightsail, Google Cloud or Azure.
A snapshot alone has two gaps: it lives in the same cloud account, and it restores all or nothing. So also dump the databases and copy the files that matter elsewhere. Run this guide's commands as root (sudo -i).
install -d -m 700 /root/pre-upgradesudo -u postgres pg_dumpall > /root/pre-upgrade/postgres-all.sqlmysqldump --all-databases --single-transaction --routines --events > /root/pre-upgrade/mysql-all.sqlpg_dumpall writes every database and role to one file; --single-transaction reads InnoDB tables without locking them (add -u root -p if root needs a password). See the pg_dump and mysqldump guides. Copy the dumps and your application folders (/var/www, /opt, home directories) off the server with rclone or rsync; the server backup checklist lists what people forget.
The dumps and the /etc archive below hold password hashes, keys and all your data. Keep /root/pre-upgrade readable by root only, and encrypt anything that leaves the server.
Record what the server runs now
This script saves what you'll compare against afterwards, plus a copy of /etc:
#!/usr/bin/env bash
set -euo pipefail
umask 077
OUT="/root/pre-upgrade"
mkdir -p "$OUT"
dpkg --get-selections > "$OUT/packages.txt"
apt-mark showmanual > "$OUT/manual-packages.txt"
apt-mark showhold > "$OUT/held-packages.txt"
systemctl list-units --type=service --state=running --no-legend --plain > "$OUT/running-services.txt"
systemctl list-unit-files --state=enabled --no-legend > "$OUT/enabled-units.txt"
ss -tlnp > "$OUT/listening-ports.txt"
cp -a /etc/apt/sources.list.d "$OUT/"
tar -czf "$OUT/etc.tar.gz" -C / etcbash /root/pre-upgrade-record.shmanual-packages.txtlists what you installed on purpose: the list to rebuild from.held-packages.txtshould be empty. Release holds withapt-mark unhold <package>.listening-ports.txtis the quickest proof later that each service came back.
Two things the script can't capture. For each Python virtual environment, save its packages with <venv>/bin/pip freeze > requirements.txt. And if you run MySQL, find accounts on the old password plugin, which MySQL 8.4 locks out by default:
SELECT User, Host FROM mysql.user WHERE plugin = 'mysql_native_password';Ubuntu's release notes recommend switching each to caching_sha2_password. This resets the password, so reuse the current one:
ALTER USER 'app'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'current-password';Run the upgrade
Bring the current release fully up to date, or the upgrade refuses to start. The phased-updates option includes updates Ubuntu is still rolling out:
apt updateapt dist-upgrade -o APT::Get::Always-Include-Phased-Updates=trueIf /run/reboot-required exists, reboot. Check free space with df -h / /boot; the download alone can be several gigabytes. Now take the snapshot.
Over SSH, the upgrader starts a spare sshd on port 1022 in case the main one breaks mid-upgrade, but doesn't open the port in your firewall. Allow it in ufw and your cloud firewall first:
ufw allow 1022/tcpFind your provider's web console too. Then run the upgrade inside a session that survives a dropped connection:
tmux new -s upgradedo-release-upgradeIf SSH drops, reconnect and run tmux attach -t upgrade. The upgrader also runs itself inside GNU screen when it's installed; screen -d -r reattaches. Expect these questions:
- Foreign packages: installed from outside the Ubuntu archive. Note them, and check them first afterwards.
- Configuration files: press
Dto see the difference. The default keeps yours and saves the package's as.dpkg-dist; taking theirs saves yours as.dpkg-old. Some packages ask as a menu. - PostgreSQL: postgresql-common may offer to upgrade the
maincluster automatically, by default with a slow but safe dump and reload inside the upgrade. Say no to do it later, on your schedule. - Obsolete packages: removed and purged, configuration included; press
dto review the list.postgresql-NNpackages are never removed automatically, so a cluster keeps its binaries.
Last, it asks to reboot; the upgrade isn't finished until it does. Once you're back on port 22, close the spare port:
ufw delete allow 1022/tcpCheck the server after the reboot
Confirm the new release, then look for units that failed to start:
lsb_release -asystemctl --failedCompare the running services with your record. Lines starting with < are services that ran before and don't now:
diff <(awk '{print $1}' /root/pre-upgrade/running-services.txt) <(systemctl list-units --type=service --state=running --no-legend --plain | awk '{print $1}')Find packages no enabled repository provides any more, leftovers from 24.04 and from the disabled repositories (2>/dev/null hides apt's scripting warning):
apt list --installed 2>/dev/null | grep ',local]'List the configuration files where you and a package disagreed, and merge what you need:
find /etc -name '*.dpkg-dist' -o -name '*.dpkg-old' -o -name '*.ucf-dist'- Repositories. Entries the upgrade switched off carry
Enabled: noin/etc/apt/sources.list.d/. Check that the vendor publishes packages for 26.04, change the suite fromnobletoresolute, delete theEnabled: noline and runapt update. - PHP-FPM. 8.5 listens on
/run/php/php8.5-fpm.sock, so sites return 502 until you updatefastcgi_pass(nginx) or runa2disconf php8.3-fpmanda2enconf php8.5-fpm(Apache). Your changes in/etc/php/8.3/don't carry over to/etc/php/8.5/, and versioned extensions such asphp8.3-mysqlneed their 8.5 packages. - PostgreSQL. Run
pg_lsclusters. Unless you let the upgrade convert it, your data is still in the 16 cluster, usually on port 5432, and an empty 18 cluster may sit on the next port. Follow upgrading PostgreSQL to a new major version, and keeppostgresql-16installed until the new cluster is checked. - MySQL. If an application can't log in, look for
mysql_native_passwordaccounts you missed. Ubuntu's notes also allowmysql_native_password=ONunder[mysqld]as a stopgap; later MySQL versions drop it. - Python. Rebuild each virtual environment, which Python's docs treat as disposable:
python3 -m venv --clear <venv>, then<venv>/bin/pip install -r requirements.txt.
Roll back if it went wrong
There is no downgrade. do-release-upgrade only moves forward, and apt can't take a whole system back a release. The way back is the snapshot:
- If the upgraded server took writes you want to keep, dump those databases and copy the dumps off first. A dump from a cluster the upgrade didn't convert loads into the restored server unchanged.
- Restore the snapshot with your provider's tools, from the guides above. Some providers restore the existing server in place; others build a new server from the snapshot, with a new IP address.
- Load the newer dumps, and point DNS at the new address if it changed.
Rehearse next time: build a second server from the snapshot, upgrade that one first, and test your sites on it before touching the real one. It's the same habit as testing a restore.
Common errors
| Message or symptom | Fix |
|---|---|
Please install all available updates for your release before upgrading. | Run apt update and the apt dist-upgrade command above. If it persists, check apt-mark showhold. |
You have not rebooted after updating a package which requires a reboot. Please reboot before upgrading. | Reboot, then run do-release-upgrade again. |
No new release found. | The LTS path isn't open, or Prompt doesn't allow it. Check /etc/update-manager/release-upgrades. |
Could not calculate the upgrade | Usually packages from PPAs or other third-party sources. The message suggests ppa-purge; details are in /var/log/dist-upgrade/main.log and apt.log. |
Not enough free disk space | Run apt clean; for /boot, remove old kernels with apt autoremove. The message names the disk and how much to free. |
| SSH dropped mid-upgrade | Log in again (or on port 1022) and reattach with tmux attach -t upgrade or screen -d -r. Don't start a second upgrade. |
| Sites return 502 after the upgrade | The PHP-FPM socket path changed to php8.5-fpm.sock. Update the web server config. |
Frequently asked questions
- Can I upgrade Ubuntu 22.04 straight to 26.04?
- No. LTS upgrades go one release at a time: 22.04 to 24.04, then 24.04 to 26.04. Back up and check the server between the two.
- When can I upgrade from 24.04 to 26.04 LTS?
- Now. Ubuntu opens LTS-to-LTS upgrades after the first point release, and 26.04.1 came out on 27 August 2026.
do-release-upgrade -cconfirms it from your server. - Can I undo an Ubuntu release upgrade?
- Not with apt or do-release-upgrade; there is no downgrade. Restore the snapshot you took before, or rebuild from your backups.
- Does do-release-upgrade delete my data?
- It leaves your own files alone, but it replaces packages, switches off third-party repositories, asks about changed config files and offers to purge obsolete packages, configuration included. That's enough to break a working site, which is why you back up first.
How this was checked
Commands, limits and prices were checked against these official pages, on October 4, 2026:
- Ubuntu Server documentation: How to upgrade your Ubuntu release
- Ubuntu 26.04 LTS release notes
- Ubuntu 26.04 LTS release notes: summary for LTS users
- Ubuntu Discourse: Ubuntu 26.04.1 LTS released
- Ubuntu meta-release-lts (the upgrade list do-release-upgrade reads)
- Ubuntu manpage: do-release-upgrade(8)
- ubuntu-release-upgrader source, resolute branch: DistUpgradeController.py
- ubuntu-release-upgrader source, resolute branch: DistUpgradeMain.py (GNU screen)
- ubuntu-release-upgrader source, resolute branch: removal_denylist.cfg
- Ubuntu packages: php8.5-fpm (resolute)
- Ubuntu packages: php8.3-fpm (noble)
- Ubuntu packages: postgresql-18 (resolute)
- Ubuntu packages: mariadb-server (resolute)
- Ubuntu packages: redis-server (resolute)
- Debian PHP packaging: FPM pool and socket paths
- Debian PHP packaging: php-fpm postinst (a2enconf)
- postgresql-common README.Debian (clusters, ports, upgrading)
- MySQL 8.4 Reference Manual: Native Pluggable Authentication
- MySQL 8.4 Reference Manual: Grant Tables
- MySQL 8.4 Reference Manual: mysqldump
- PostgreSQL documentation: pg_dumpall
- Python documentation: venv
- apt source: [installed,local] in apt list
- Ubuntu manpage: dpkg(1) (.dpkg-dist and .dpkg-old)
- Ubuntu manpage: ucf(1)
- Ubuntu manpage: tmux(1)
- Ubuntu manpage: screen(1)
- Ubuntu manpage: ufw(8)