How to Upgrade from OpenBSD 7.8 to 7.9 on amd64 Servers (2026)
Prerequisites and Pre-Upgrade Checklist
Before touching a single file, spend five minutes confirming your environment. OpenBSD upgrades are clean and reliable when you follow the prescribed path, but skipping the checklist is how you end up with a non-booting server at 2 AM.
- [ ] Running OpenBSD 7.8 on amd64 (sequential upgrades only — skipping releases is unsupported)
- [ ] Root access or
doas/sudoequivalent configured - [ ] At least 1 GB free in
/and 500 MB free in/usr(check withdf -h) - [ ] Snapshot or offsite backup of
/etc,/var, and any application data taken within the last 24 hours - [ ] Console or out-of-band access (IPMI, serial) — you will reboot during this process
- [ ] The 7.9 errata page reviewed at
https://www.openbsd.org/errata79.html
Estimated time: 30–50 minutes (depending on mirror speed and number of installed packages)
Verify current OpenBSD version and architecture
Run these commands and compare the output to the expected values before proceeding:
| Task | Command | Expected Output |
|---|---|---|
| Confirm OS version | uname -a | OpenBSD hostname 7.8 GENERIC.MP amd64 |
| Check free disk space | df -h /usr | At least 500M available |
| Confirm architecture | machine | amd64 |
| List installed packages | pkg_info | wc -l | Any number; note it for post-upgrade comparison |
| Verify existing signify keys | ls /etc/signify/ | Should contain openbsd-78-*.pub keys |
Backup critical data and configuration files
At minimum, archive /etc and your application configs:
doas tar -czf /root/etc-backup-$(date +%Y%m%d).tar.gz /etc
doas tar -czf /root/var-backup-$(date +%Y%m%d).tar.gz /var/db /var/cron
If your host provider supports snapshots (DigitalOcean, Vultr, Linode), take one now. A block-level snapshot is your fastest rollback option if something goes wrong.
Review the 7.9 errata page before starting
OpenBSD 7.9 was released May 19, 2026 (the 60th OpenBSD release). Post-release patches accumulate quickly. Checking the errata page at https://www.openbsd.org/errata79.html before upgrading means you'll know exactly which syspatch entries to expect after the upgrade completes.
Verifying Release Signatures with signify(1)
OpenBSD ships signify(1) in base specifically so you never have to trust a mirror blindly. Every install set is signed with an Ed25519 key, and verification takes under ten seconds. Do not skip this step — it's the difference between installing genuine OpenBSD and installing whatever a compromised mirror decided to serve you.
Understanding OpenBSD's signify tool and why it matters
OpenBSD uses four distinct keypairs for 7.9, each scoped to a specific trust domain:
| Key File | Purpose | When Used |
|---|---|---|
| openbsd-79-base.pub | Signs install sets (base79.tgz, etc.) | During install/upgrade |
| openbsd-79-fw.pub | Signs firmware packages | fw_update |
| openbsd-79-pkg.pub | Signs binary packages from ports | pkg_add |
| openbsd-79-syspatch.pub | Signs post-release security patches | syspatch |
Downloading and verifying the 7.9 install sets
Create the working directory and drop the public key in place:
doas mkdir -p /home/_upgrade
cd /home/_upgrade
Create the base public key file. The exact key string from the 7.9 release announcement is:
cat > openbsd-79-base.pub << 'EOF'
untrusted comment: openbsd 7.9 base public key
RWTSdNN9A3yvWNn7mUjXwv9DOCOUnyfuV+mq1iGPIfD+NhN8EYnEQ1at
EOF
After downloading the install sets (covered in the next section), verify them:
signify -C -p openbsd-79-base.pub -x SHA256.sig
Successful output looks like:
Checked SHA256 (bsd)
Checked SHA256 (bsd.mp)
Checked SHA256 (bsd.rd)
Checked SHA256 (base79.tgz)
Checked SHA256 (comp79.tgz)
Checked SHA256 (man79.tgz)
Checked SHA256 (game79.tgz)
If any line reads FAIL instead of Checked, stop immediately.
What to do if signature verification fails
A verification failure means either the file was corrupted in transit or the mirror is compromised. Delete every file in /home/_upgrade, switch to a different mirror (preferably one geographically distinct from your first choice), re-download everything, and verify again. Never proceed past a signify failure under any circumstances.
Step 1 — Download the 7.9 Install Sets via FTP Mirror
OpenBSD's ftp(1) client handles HTTP and FTP mirrors transparently. You need the ramdisk kernel (bsd.rd) because it's what lets you run the upgrade installer from the running system without physical media.
Choosing a geographically close FTP mirror
Pick a mirror from https://www.openbsd.org/ftp.html. For this example we use cdn.openbsd.org, which is GeoDNS-routed and works well globally. Substitute your closest regional mirror for faster throughput.
Fetching the upgrade sets with ftp(1)
cd /home/_upgrade
BASE="https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64"
for FILE in \
bsd \
bsd.mp \
bsd.rd \
base79.tgz \
comp79.tgz \
man79.tgz \
SHA256.sig; do
ftp -V "${BASE}/${FILE}"
done
If you prefer to fetch everything in one shot and don't need manual control:
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/SHA256.sig"
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/bsd"
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/bsd.mp"
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/bsd.rd"
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/base79.tgz"
ftp -V "https://cdn.openbsd.org/pub/OpenBSD/7.9/amd64/comp79.tgz"
Organizing downloaded files in /home/_upgrade
After downloading, verify the directory looks like this:
ls -lh /home/_upgrade/
-rw-r--r-- 1 root wheel 21M May 19 10:14 base79.tgz
-rw-r--r-- 1 root wheel 43M May 19 10:14 bsd
-rw-r--r-- 1 root wheel 43M May 19 10:15 bsd.mp
-rw-r--r-- 1 root wheel 5.2M May 19 10:15 bsd.rd
-rw-r--r-- 1 root wheel 67M May 19 10:16 comp79.tgz
-rw-r--r-- 1 root wheel 9.1M May 19 10:17 man79.tgz
-rw-r--r-- 1 root wheel 2.1K May 19 10:13 SHA256.sig
-rw-r--r-- 1 root wheel 104 May 19 10:13 openbsd-79-base.pub
Now run signify verification as shown in the previous section before proceeding.
Note:
bsd.rdis the ramdisk kernel. It contains a self-contained installer environment and is the safest way to upgrade — it doesn't depend on any userland tools from your existing 7.8 installation.
Step 2 — Boot into bsd.rd and Run the Upgrade Installer
Booting bsd.rd from the running system is the cleanest upgrade path. The ramdisk kernel mounts nothing from your existing installation during the extraction phase, which avoids file-in-use conflicts that can corrupt an in-place upgrade.
Booting the ramdisk kernel from the running system
Copy bsd.rd to the root filesystem so the bootloader can find it:
doas cp /home/_upgrade/bsd.rd /bsd.rd
Then reboot and interrupt the bootloader countdown (press Enter or Space at the boot> prompt):
Using drive 0, partition 3.
Loading...
probing: pc0 com0 mem[638K 3326M a20=on]
disk: hd0+ hd1+
>> OpenBSD/amd64 BOOT 3.67
boot> boot /bsd.rd
Navigating the interactive upgrade prompts
Once the ramdisk kernel boots, you'll land at the installer prompt. Choose (U)pgrade:
Welcome to the OpenBSD/amd64 7.9 installation program.
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? u
Which disk is the root disk? [sd0] (press Enter to accept)
sd0 has been read.
Root partition is /dev/sd0a.
Checking system ...
/dev/sd0a: 14812 files, 543212 used, 421098 free
When prompted for the install set source, point to your local directory:
Install set location? (cd0 disk http or 'done') [http] disk
Available disks: sd0.
Which disk contains the install media? sd0
Pathname to the sets? (or 'done') [7.9/amd64] /home/_upgrade
Selecting install sets and skipping unnecessary components
For a typical amd64 server, here's the recommended include/exclude decision for each set:
| Install Set | Include? | Reason |
|---|---|---|
| bsd (UP kernel) | No — use bsd.mp | Servers almost always have multiple cores |
| bsd.mp (MP kernel) | Yes | Multi-processor kernel; required for modern hardware |
| base79.tgz | Yes | Base system — mandatory |
| comp79.tgz | Yes | Compiler toolchain; needed for ports and kernel rebuilds |
| man79.tgz | Optional | Include if you reference man pages locally |
| game79.tgz | No | No games on production servers |
| xbase79.tgz | No | X11 base — not needed on headless servers |
| xfont79.tgz | No | X11 fonts — skip |
| xserv79.tgz | No | X11 server — skip |
| xshare79.tgz | No | X11 shared data — skip |
The installer will extract the selected sets, install the new kernels, and prompt you to reboot. After rebooting, you'll come up on OpenBSD 7.9 with the old userland — that's expected. The next steps finish the job.
Step 3 — Apply 7.9-Specific amd64 Post-Upgrade Configuration
OpenBSD 7.9 introduces several amd64-specific kernel and scheduler changes that require conscious configuration decisions. Two of them — the hybrid CPU scheduler and the DM PDE zero-fill fix — directly affect server stability and performance.
Understanding the new MAXCPUs increase to 255 on amd64
OpenBSD 7.9 raises the MAXCPUS limit on amd64 from the previous ceiling to 255, enabling support for high-core-count server platforms (AMD EPYC Genoa and similar). No configuration change is needed to take advantage of this — the kernel detects and onlines additional CPUs automatically.
Configuring hw.blockcpu sysctl for hybrid CPU scheduling
This is the headline kernel feature for amd64 in 7.9. The hw.blockcpu sysctl lets you exclude CPU classes from the scheduler using a four-letter vocabulary:
| Letter | CPU Class | Typical Speed |
|---|---|---|
| S | SMT/Hyperthreading sibling threads | ~50% of physical core |
| P | Regular performance cores | 100% baseline |
| E | Efficient cores | ~50–80% of P core |
| L | Lethargic cores | Slower than E |
The default is SL — SMT siblings and lethargic cores are blocked from the scheduler on systems where they exist. Check your current state:
# Before adjustment — see how many CPUs the scheduler sees
sysctl hw.ncpufound hw.ncpuonline hw.smt
hw.ncpufound=16
hw.ncpuonline=8
hw.smt=0
To explicitly exclude SMT siblings and lethargic cores (the recommended default for most servers):
doas sysctl hw.blockcpu=SL
hw.blockcpu: -> SL
To make this persistent across reboots, add it to /etc/sysctl.conf:
echo 'hw.blockcpu=SL' | doas tee -a /etc/sysctl.conf
Verify the effect with top(1) — you should see only the physical P-cores appearing as active:
sysctl hw.ncpuonline
hw.ncpuonline=8
Note:
hw.blockcpuis a runtime sysctl — it takes effect immediately without a reboot and does not require kernel recompilation. This feature is currently implemented on amd64 and arm64 only.
Addressing the AMD Zen/Zen+ floating point state leak mitigation
OpenBSD 7.9 mitigates a floating-point register state leak observed on AMD Zen 1 and Zen+ microarchitectures. This is applied automatically in the kernel — no sysctl or configuration change is required. Affected users (Ryzen 1000 series, EPYC Naples) will see the mitigation confirmed in dmesg:
dmesg | grep -i zen
cpu0: AMD Ryzen 7 1700 (Zen), FP state leak mitigation active
Verifying the DM PTE/PDE zero-fill fix for systems with over 512GB RAM
If your server has more than 512 GB of RAM, this fix is critical — the previous bug could cause subtle memory corruption during heavy paging. Confirm the fix is active:
dmesg | grep -i 'pde\|pte\|zero'
On affected (large memory) systems you'll see kernel messages confirming the DM PDE pages are being zeroed. On systems under 512 GB, the fix is present but the specific code path is rarely triggered.
Step 4 — Run sysmerge and pkg_add -u to Finalize the Upgrade
sysmerge(8) and pkg_add -u are the two commands that finish converting your system from 7.8 to 7.9 at the userland and package level. Run them in this order — sysmerge first, packages second.
Running sysmerge(8) to reconcile /etc configuration files
sysmerge compares the new base system's default /etc files against your running configuration and presents diffs for files that conflict:
doas sysmerge -d
Typical interactive output for a server with minor customizations:
*** /etc/login.conf (merged)
*** /etc/rc.conf.local (local, keeping yours)
*** /etc/ssh/sshd_config (conflict — interactive merge required)
== Merging /etc/ssh/sshd_config ==
Yours: PermitRootLogin no
New: PermitRootLogin prohibit-password
(k)eep, (n)ew, (m)erge, (d)iff? m
Common strategy: keep your values for sshd_config, pf.conf, and rc.conf.local; accept new values for login.conf, protocols, and services (these rarely have local modifications and new versions add entries).
Updating all installed packages with pkg_add -u
After sysmerge completes, update every installed package:
doas pkg_add -u -Dsnap
Quirks 6.119 signed on 2026-05-19T10:00:00Z
Dependencies of quirks-6.119 already installed
Updating curl-8.8.0 -> curl-8.9.1: ok
Updating python-3.11.9 -> python-3.11.10: ok
Updating vim-9.1.200 -> vim-9.1.350: ok
...
The -Dsnap flag instructs pkg_add to fetch packages matching the installed release (7.9), not snapshots — despite its name, it's the correct flag for a release upgrade.
Verifying syspatch availability for 7.9
Check for post-release security patches immediately after upgrading:
doas syspatch -c
001_meltdown
002_spectre
Install available patches:
doas syspatch
syspatch uses openbsd-79-syspatch.pub (key: RWTJmz/ur68S9e26/JVRr7T88lAPZIF3YgZ3w2lDnf/frAxTerC/DrZ6) to verify patch signatures automatically — you don't need to manage this key manually.
Finally, update firmware packages:
doas fw_update
fw_update uses openbsd-79-fw.pub (key: RWQdmBb/OCe1hXE08xCj5VLnBpGpphy7kYPdU3oWyfnrwswjtl8K385E) to verify firmware downloads. This is especially important on servers with Intel NICs (iwx, iwm) or AMD GPUs.
Common Issues and Fixes After Upgrading to OpenBSD 7.9
Error: amdgpu hang on ThinkPad X13 Gen 6 (Panel Self Refresh)
Cause: Panel Self Refresh (PSR) in the amdgpu driver caused intermittent display hangs on ThinkPad X13 Gen 6 hardware under 7.8.
Fix: OpenBSD 7.9 explicitly disables PSR in the amdgpu driver. Confirm it's disabled after upgrading:
dmesg | grep -i 'amdgpu\|psr'
amdgpu0: PSR disabled
amdgpu0: 16 CUs, 1800 MHz, 4096 MB VRAM
If your dmesg still shows PSR enabled after upgrading, verify you actually booted the new 7.9 kernel with uname -r. A common mistake is having the new userland but still running the old kernel because bsd.mp wasn't copied correctly.
Error: Kernel panic or instability on machines with >512GB RAM
Cause: Under OpenBSD 7.8, DM PTE/PDE pages were not zeroed before use. On systems with more than 512 GB of RAM, this could lead to memory corruption during high-paging workloads.
Fix: This is corrected automatically in the 7.9 kernel. After upgrading, confirm the running kernel is 7.9:
uname -r
7.9
If you're still experiencing instability on a >512 GB system post-upgrade, check whether an ECC memory error is the underlying cause — the OpenBSD fix resolves the kernel bug, but hardware-level memory faults are a separate issue. Check dmesg | grep -i 'ecc\|mce'.
Error: Package dependency conflicts after pkg_add -u
Cause: Some packages hard-code version constraints that become unsatisfiable when the shared library versions advance with a new release.
Fix: Run pkg_add -u with the -V (verbose) flag to identify the specific conflict:
doas pkg_add -uV 2>&1 | grep -i 'conflict\|error'
For most conflicts, the fix is to remove the old package and reinstall the new version:
doas pkg_delete conflicting-package-name
doas pkg_add conflicting-package-name
If the conflict involves a package no longer in the 7.9 ports tree, check https://openports.pl for the package's current status and any replacement.
Troubleshooting Reference Table
| Symptom | Likely Cause | Recommended Fix |
|---|---|---|
| Display hang on ThinkPad X13 Gen 6 | amdgpu PSR not disabled | Verify 7.9 kernel is booted; check dmesg | grep psr |
| Memory corruption on >512GB systems | DM PDE not zeroed (7.8 bug) | Ensure 7.9 kernel is active with uname -r |
| pkg_add -u fails with conflict | Library version mismatch | pkg_delete old package; re-add with pkg_add |
| syspatch fails to verify patches | Wrong pubkey or corrupted download | Re-download; confirm openbsd-79-syspatch.pub key |
| hw.blockcpu sysctl not found | Running old 7.8 kernel | Reboot into new bsd.mp kernel |
| FP state leak warnings in dmesg | AMD Zen/Zen+ (expected) | Informational only; mitigation is active |
Validating the Upgraded System and Kernel Version
With the upgrade complete, spend a few minutes confirming everything is running as expected. Don't just assume — verify.
Confirming kernel version and build date with uname -a
uname -a
OpenBSD hostname.example.com 7.9 GENERIC.MP#1 amd64
The GENERIC.MP label confirms you're running the multi-processor kernel. The #1 is the build revision. If you see GENERIC without .MP on a multi-core server, you're running the uniprocessor kernel — re-copy bsd.mp to /bsd and reboot.
Checking CPU scheduler behavior with top(1) and systat(1)
Verify the scheduler sees the correct number of online CPUs:
sysctl hw.ncpufound hw.ncpuonline
hw.ncpufound=16
hw.ncpuonline=8
The difference between ncpufound and ncpuonline reflects your hw.blockcpu setting. In this example, hw.blockcpu=SL has excluded the 8 SMT sibling threads, leaving 8 physical P-cores active.
Confirm this visually in top(1):
top -d 1
The CPU bar count in the header should match hw.ncpuonline, not hw.ncpufound.
Reviewing dmesg for hardware driver warnings post-upgrade
A quick scan for anomalies:
dmesg | grep -i error
# Healthy system: no output, or only expected informational lines
Also check:
dmesg | grep -i 'fail\|warning\|panic'
Common benign warnings include pciide DMA mode messages and USB device re-enumeration. A line containing panic in dmesg that you don't have from the previous boot indicates a real problem — check /var/crash for a core dump and open an issue at https://bugs.openbsd.org.
FAQ: OpenBSD 7.8 to 7.9 Upgrade on amd64
Q: Can I skip 7.8 and upgrade directly from 7.7 to 7.9?
No. The OpenBSD project officially recommends sequential upgrades — 7.7 → 7.8 → 7.9. The installer's upgrade path is designed for one-version hops; sysmerge diff logic, package dependency resolution, and kernel ABI assumptions all target the immediately preceding release. Attempting to skip a version often results in sysmerge conflicts that are difficult to resolve correctly, and package databases may fail to migrate cleanly. Upgrade to 7.8 first using the same bsd.rd method described here, validate the system, then proceed to 7.9.
Q: Does the new hybrid CPU scheduler (hw.blockcpu) require kernel recompilation?
No. hw.blockcpu is a standard sysctl(8) variable — it takes effect at runtime with no reboot and no kernel recompilation required. You can change it live: doas sysctl hw.blockcpu=SL to exclude SMT and lethargic cores, or doas sysctl hw.blockcpu= (empty string) to restore all CPUs to the scheduler. To persist the setting across reboots, add hw.blockcpu=SL to /etc/sysctl.conf. This feature is implemented in the GENERIC.MP kernel on amd64 and arm64 — no custom kernel config is needed.
Q: How do I roll back to 7.8 if the upgrade causes issues?
The cleanest rollback is restoring from the block-level snapshot you took before starting. If your provider (DigitalOcean, Vultr, Linode) supports snapshot restore, use it — it's a 5-minute operation that gets you exactly back to 7.8. If you only have the /etc tarball backup, you'll need to reinstall 7.8 from media (using bsd.rd for 7.8) and restore configuration files afterward. There is no supported in-place downgrade path in OpenBSD — the project does not provide downgrade tooling. This is why the pre-upgrade snapshot is non-negotiable, not optional.