Guides

Upgrade Debian 12 (Bookworm) to Debian 13 (Trixie) on a server, step by step

Back up, fully update Bookworm, switch the sources to trixie, run apt full-upgrade inside tmux and check what changed — the safe in-place upgrade on a VPS.

Published ~13 min read

To upgrade Debian 12 (Bookworm) to Debian 13 (Trixie) in place: make a backup, bring Bookworm fully up to date and reboot, set third-party repositories aside, switch the APT sources from bookworm to trixie, then run apt upgrade --without-new-pkgs followed by apt full-upgrade, and reboot. On a server, do all of it inside tmux or from the VNC console, so a dropped SSH session cannot stop the upgrade halfway.

the short version · as root
tmux new -s upgrade                       # run everything inside tmux
apt update && apt full-upgrade            # finish Debian 12 first
reboot

tmux new -s upgrade                       # after logging in again
# move third-party .list/.sources files out of /etc/apt/sources.list.d/ first (see step 3)
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list /etc/apt/sources.list.d/*
apt update
apt upgrade --without-new-pkgs            # pass 1: upgrade what needs no new packages
apt full-upgrade                          # pass 2: everything else
reboot

cat /etc/os-release                       # VERSION="13 (trixie)"

That is the whole procedure. The rest of this guide covers what to check before you run it, what to answer at the prompts, and the Trixie changes that can catch a server out.

What should I do before I start?

  • Make a backup you can restore. On a VPS, a snapshot taken right before the upgrade is the fastest way back. Also keep a copy of the package state and /etc off the server. Debian’s release notes recommend saving /etc, /var/lib/dpkg, /var/lib/apt/extended_states and the output of dpkg --get-selections '*'.
  • Check free space. df -h / /boot. If /boot is a separate partition, the release notes ask for at least 768 MB in size with about 300 MB free. Keep a few GB free on /; step 5 shows the exact figure. Our guide to checking disk usage helps if space is short.
  • Read the official release notes, especially chapter 5, “Issues to be aware of for trixie”: debian.org/releases/trixie/release-notes. The server-relevant items are summarised below.
  • List your third-party repositories with ls /etc/apt/sources.list.d/. Docker, PostgreSQL’s PGDG, NodeSource, PHP builds and similar vendors each decide when to support a new release. Check each vendor’s documentation for trixie before you rely on it afterwards.
  • Check for held and broken packages. apt-mark showhold should print nothing (or apt-mark unhold them), and dpkg --audit should be silent.
  • Deal with the changes that need action first. DSA keys stop working and /etc/sysctl.conf stops being read; MariaDB needs a clean shutdown. All of it is in what changed in Trixie.
  • Have a way in that does not depend on SSH. On a VMHeaven VPS, the panel has backups and a VNC console that keeps working when the network on the server does not come back.
save package state and /etc · as root
dpkg --get-selections '*' > /root/selections-bookworm.txt
tar -czf /root/pre-trixie.tgz /etc /var/lib/dpkg /var/lib/apt/extended_states /root/selections-bookworm.txt
# then copy /root/pre-trixie.tgz somewhere other than this server

How do I upgrade Debian 12 to 13, step by step?

  1. 1Become root and start tmux
    as root
    sudo -i
    apt install -y tmux
    tmux new -s upgrade

    If your SSH connection drops, log in again and run tmux attach -t upgrade. The upgrade keeps running in the meantime, and the Debian release notes recommend exactly this. Why connections drop and how to prevent it is covered in SSH broken pipe.

  2. 2Finish Debian 12 and reboot
    as root
    apt update && apt full-upgrade
    reboot
    # after logging in again:
    sudo -i
    tmux new -s upgrade
    cat /etc/debian_version          # the latest 12.x point release
    apt policy openssh-server        # Installed: 1:9.2p1-2+deb12u7 or later

    The OpenSSH check matters. The release notes warn that an older Bookworm OpenSSH can leave a remote system unreachable if an upgrade run over SSH is interrupted. The fix arrives with the normal Bookworm updates, so this step installs it.

  3. 3Set third-party repositories aside
    as root · example for a Docker repo
    mkdir -p /root/apt-held
    mv /etc/apt/sources.list.d/docker.list /root/apt-held/     # repeat for each third-party file

    Move every file that is not Debian’s own out of /etc/apt/sources.list.d/. Also delete or comment out any bookworm-backports or proposed-updates lines, and remove APT pinning in /etc/apt/preferences.d/ that targets Bookworm. The release notes ask for all three.

  4. 4Point Debian's sources at trixie
    as root
    sed -i 's/bookworm/trixie/g' /etc/apt/sources.list /etc/apt/sources.list.d/*
    grep -rn 'trixie' /etc/apt/sources.list /etc/apt/sources.list.d/
    apt update

    Debian’s sources live in /etc/apt/sources.list (one-line format) or in /etc/apt/sources.list.d/debian.sources (deb822 format), depending on how the system was installed. The glob covers both. If one of the paths does not exist, sed prints an error for it, which is harmless. Afterwards every Debian entry should name trixie, trixie-updates or trixie-security. If your sources say stable instead of a codename, change that to trixie too: with a codename, the next release never arrives by surprise.

    apt update has to finish without errors. A NO_PUBKEY error almost always comes from a third-party file you missed (see GPG error: NO_PUBKEY).

  5. 5Check the space the upgrade needs
    as root
    apt -o APT::Get::Trivial-Only=true full-upgrade

    This changes nothing. It prints “Need to get …” and “After this operation, … of additional disk space will be used” and then stops. Compare both figures with df -h.

  6. 6Run the minimal upgrade
    as root
    apt upgrade --without-new-pkgs

    This upgrades every package that can be upgraded without installing or removing anything else. The release notes recommend it as a first pass because it keeps the second pass smaller and safer, especially on servers that are short on space.

  7. 7Run the full upgrade
    as root
    apt full-upgrade

    This installs the new kernel, the new library versions and the new versions of your services, and it removes packages that Trixie replaces. Stay at the terminal: it stops for questions, described in the next section. If it fails with a dependency problem, apt full-upgrade -o APT::Immediate-Configure=0 is the workaround the release notes give.

  8. 8Fix what Trixie stops reading, then reboot

    Before rebooting, go through what changed in Trixie. At minimum, move /etc/sysctl.conf settings and check SSH keys and network interface names. Then run sshd -t (no output means the SSH config is valid) and reboot.

What do I answer at the config-file prompts?

If you edited a configuration file that a package now ships in a new version, dpkg stops and asks:

dpkg prompt
Configuration file '/etc/example.conf'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
  • Press D first and read the diff. If the differences are only your own changes, keep yours (N). If the new version adds something you want and you changed little, take it (Y) and apply your changes again afterwards.
  • Nothing is lost either way. If you keep yours, the new version is saved next to it as .dpkg-dist. If you take the new one, yours is saved as .dpkg-old. After the upgrade, find /etc -name '*.dpkg-*' -o -name '*.ucf-*' lists every pair to review.
  • sshd_config gets a menu instead of the Y/N prompt, because it is managed by ucf. Use “show the differences”, and if in doubt choose keep the local version currently installed. Taking the maintainer’s version resets your Port, PasswordAuthentication and PermitRootLogin lines to Debian’s defaults, which can lock you out or switch password logins back on. In the long run, move your SSH settings into /etc/ssh/sshd_config.d/*.conf, and the prompt goes away.
  • Other questions: “Restart services during package upgrades without asking?” can be answered Yes on a server you upgrade inside tmux. apt-listchanges shows news entries in a pager; read them and press q. If GRUB asks where to install itself, choose the whole disk (for example /dev/vda or /dev/sda), not a partition. lsblk in a second tmux window (Ctrl+b c) shows which one.

What changed in Trixie that can affect a server?

All of the following is taken from the Debian 13 release notes. Check the current version of the notes before you upgrade, because they are updated with point releases.

/etc/sysctl.conf is no longer read

systemd-sysctl in Trixie ignores /etc/sysctl.conf. Anything you set there, such as net.ipv4.ip_forward = 1 for a WireGuard server or tuned network buffers, silently stops applying after the reboot. Move it to a file in /etc/sysctl.d/:

as root
grep -Ev '^[[:space:]]*(#|$)' /etc/sysctl.conf                              # anything listed stops applying
grep -Ev '^[[:space:]]*(#|$)' /etc/sysctl.conf > /etc/sysctl.d/99-local.conf
sysctl --system

/tmp is now a tmpfs in RAM

From the first reboot into Trixie, /tmp is held in memory and may use up to half of the RAM. On a small VPS, a job that writes large files to /tmp now consumes memory and can run into the OOM killer. Files left in the old /tmp are hidden under the new mount. If /tmp has its own entry in /etc/fstab, nothing changes. To keep /tmp on disk, run systemctl mask tmp.mount and reboot; to change its size limit, use systemctl edit tmp.mount. findmnt /tmp shows which one you have. New installations also delete old files from /tmp and /var/tmp automatically. Upgraded systems receive /etc/tmpfiles.d/tmp.conf, which keeps the old behaviour.

OpenSSH drops DSA keys completely

The OpenSSH in Trixie no longer supports DSA (ssh-dss) keys, not even when they are enabled explicitly in the configuration. If anyone logs in with one, key login stops working after the upgrade. Check, and replace such keys with Ed25519 before you start:

any DSA keys?
grep -l ssh-dss /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/null
ssh-keygen -t ed25519      # on the client, then ssh-copy-id user@server

sshd also no longer reads ~/.pam_environment. Set those variables in the shell’s startup files instead.

last, lastb and lastlog are gone

Because of their year-2038 problem, these commands were removed. Use lslogins from util-linux, or install the replacements: wtmpdb (with libpam-wtmpdb) provides a new last, and lastlog2 (with libpam-lastlog2) replaces lastlog. Scripts that parse last output need checking. The old /var/log/wtmp*, btmp* and lastlog* files can be deleted after the upgrade.

Network interface names can change

The release notes describe two cases where Trixie names a network interface differently from Bookworm: the Intel i40e driver, and firmware that reports PCI slot numbers through the ACPI _SUN object, which systemd 257 now uses. Names such as ens3 or ens18, common on virtual machines, are built from slot numbers. If the name changes, the network configuration no longer matches and the server boots without network. Pinning the current name takes a minute:

as root · use your own name and MAC from ip -br link
ip -br link                     # e.g.  ens18   UP   aa:bb:cc:dd:ee:ff
cat > /etc/systemd/network/10-ens18.link <<'EOF'
[Match]
MACAddress=aa:bb:cc:dd:ee:ff

[Link]
Name=ens18
EOF
update-initramfs -u

Major versions of the usual server software

  • MariaDB 10.11 becomes 11.8. MariaDB cannot recover a crashed database across major versions, so the release notes ask for a clean shutdown first: systemctl stop mariadb before step 6, and check that journalctl -u mariadb -n 20 shows “Shutdown complete”.
  • PHP 8.2 becomes 8.4. nginx or Apache configs that name the php8.2-fpm socket have to point to /run/php/php8.4-fpm.sock once you switch, and extensions installed per version (php8.2-*) need their 8.4 counterparts.
  • PostgreSQL 15 becomes 17. Debian does not migrate your data on its own: the existing cluster keeps running on 15 until you move it with pg_upgradecluster, as described in /usr/share/doc/postgresql-common/README.Debian.gz.
  • APT 3. Trixie ships a new major version of APT. Among other things, it can convert your sources to the deb822 format with apt modernize-sources (see the next section).
  • 32-bit i386 can no longer be upgraded, because Trixie has no official i386 kernel. dpkg --print-architecture should say amd64.

What do I check after the upgrade?

after the reboot · as root
cat /etc/os-release              # PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
cat /etc/debian_version          # 13.x
uname -r                         # a 6.12 kernel
systemctl --failed               # services that did not start
journalctl -b -p err             # errors since this boot
ip -br addr                      # the interface is up and has its address

How to check your Linux version explains the other places a version number shows up. Then clean up and bring the third-party repositories back:

clean-up · as root
# put third-party repos back once each vendor supports trixie
sed -i 's/bookworm/trixie/g' /root/apt-held/docker.list
mv /root/apt-held/docker.list /etc/apt/sources.list.d/
apt update

apt list '?obsolete'             # packages that no repository offers any more: review first
apt autoremove --purge           # dependencies nothing needs now
apt modernize-sources            # convert one-line sources to deb822 .sources files

Review ?obsolete before you purge anything. Packages from a third-party repository you have not re-enabled yet show up there too, and so do old PHP or PostgreSQL versions you still need until their data is migrated.

What if the upgrade breaks?

  • The SSH session dropped. Log in again and run tmux attach -t upgrade. If apt was killed with it, run dpkg --configure -a, then apt full-upgrade again. See dpkg was interrupted.
  • apt update reports a missing key or package. See NO_PUBKEY and Unable to locate package. Most often a source line still says bookworm or has a typo.
  • Dependency errors in full-upgrade. Try apt -f install, then apt full-upgrade -o APT::Immediate-Configure=0. If a package you no longer need blocks the upgrade, remove it and run the upgrade again.
  • No network or no boot after the reboot. Use the VNC console. A renamed interface is fixed by editing /etc/network/interfaces or adding the .link file above. If it does not boot at all, pick the previous kernel in the GRUB menu on the console, boot your provider’s rescue system if it has one and repair the disk from there, or restore the backup you took before starting.

Can I go straight from Debian 11 to 13?

No. Debian supports upgrades from one release to the next only. Upgrade Debian 11 (Bullseye) to 12 first, following the Bookworm release notes, reboot, check that everything works, and then follow this guide. Debian 11’s LTS support ended on 31 August 2026 according to the Debian LTS wiki, so a Bullseye server should move now.

How long is Debian 12 still supported?

Bookworm’s regular security support from the Debian security team ended in mid-2026. Since then it has been covered by Debian LTS, which Debian lists until 30 June 2028 for a limited set of architectures, amd64 among them. Check the current dates on debian.org/releases/bookworm and in the Debian LTS wiki. LTS keeps a server patched, but new software versions arrive only with Trixie, so planning the upgrade now is easier than doing it under pressure later.

Should I upgrade in place or reinstall?

Upgrade in place when the server has grown over the years: hand-written configs, data in several places, services nobody has documented. Debian’s in-place upgrade is designed for that and keeps everything. Reinstall when the server can be rebuilt from code (a Compose file, an Ansible playbook, a backup you restore regularly). A clean Trixie install then takes less time than the upgrade and carries no leftovers.

VMHeaven offers a ready Debian 13 template on all its KVM plans (the Debian VPS page lists them), but a reinstall from the panel wipes the disk. Copy your data off the server, or to a second server, and test the restore before you click it.

Frequently asked

Can I upgrade straight from Debian 11 to Debian 13?

No. Debian supports upgrades only from one release to the next, so a Debian 11 (Bullseye) server goes to 12 first, following the Bookworm release notes, is rebooted and checked, and then goes from 12 to 13. Skipping a release leaves package transitions half done and is not tested by Debian.

How long does the upgrade from Debian 12 to 13 take?

It depends on how many packages are installed and on disk and network speed, so plan for an hour of attention including two reboots rather than a fixed number. Most of the time goes into downloading and unpacking during 'apt full-upgrade', and it stops for configuration-file questions, so stay at the terminal. Run it inside tmux so a dropped connection doesn't interrupt it.

Will my data and configuration be kept?

Yes. An in-place upgrade keeps /home, /var/lib and everything else, and a configuration file you changed is kept unless you choose the package maintainer's version at a prompt. The other version is saved next to it as .dpkg-dist or .dpkg-old. Services that change major version can need follow-up: PHP 8.2 to 8.4 socket paths, PostgreSQL 15 to 17 data via pg_upgradecluster, and settings in /etc/sysctl.conf, which Trixie no longer reads.

Should I reinstall Debian 13 instead of upgrading?

Reinstall when the server can be rebuilt from code or a tested backup. A fresh Debian 13 install is quick and carries no leftovers. Upgrade in place when the server holds years of hand-made configuration. A reinstall from a hosting panel wipes the disk, so copy your data off the server and test the restore before you start.

Related articles

All guides