SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

Control snap updates on Ubuntu Server

Snapd refreshes on its own schedule and ignores unattended-upgrades. Hold a snap, set a refresh window, read snap changes, and revert a bad revision.

Why a snap looks stuck on an old revision

Snap updates on Ubuntu Server are driven by snapd, not by APT (advanced package tool) and not by unattended-upgrades. snapd contacts the Snap Store on its own schedule, four times a day by default, and installs any new revision of a snap you have installed. A snap that sits on an old revision is stuck for one of five reasons, and each reason has a command that names it.

snap list
snap refresh --list
snap refresh --time

The snap is held. snap list prints a Notes column, and a snap under a refresh hold carries the word held in it. The scheduler skips that snap until the hold expires or you remove it.

The channel is not moving. The Tracking column shows which channel the snap follows, written as <track>/<risk>, such as latest/stable or 5.21/stable. A track is a version line. 5.21/stable keeps receiving fixes inside 5.21 and never jumps to 6.x, so a server that looks behind another server may be following an older track and behaving correctly. snap info <name> lists the channels on offer, and sudo snap refresh --channel=latest/stable <name> moves the snap to a different one.

The revision is still rolling out. snap refresh --list names every snap with an update waiting. When it reports nothing while another machine already runs a newer revision, the usual cause is a progressive release: the store hands a new revision to a growing share of machines instead of to all of them at once. Nothing is broken. The revision arrives on its own.

The refresh ran and was rolled back. snap changes shows a status of Undone in that case, which means snapd started the refresh, hit a failing task, and put the old revision back. Read that list before you decide nothing happened.

snapd cannot reach the store. sudo journalctl -u snapd records each attempt. A proxy, a restrictive egress firewall, or a DNS (domain name system) failure shows up there as a failed refresh rather than as a message on your console.

How the snap refresh schedule actually works

snap refresh --time prints the schedule and the two timestamps that matter. The output looks like this:

timer: 00:00~24:00/4
last: today at 07:47 BST
next: today at 12:13 BST

Read 00:00~24:00/4 as four refresh attempts spread across a window that runs from midnight to midnight. The tilde means snapd picks a random moment inside each span instead of a fixed one, so every machine in the world does not contact the store on the same second. On a server, the practical result is four unattended maintenance events a day, at times you did not choose.

That schedule lives inside snapd's own state, so there is no refresh timer unit in systemd for you to mask. Stopping snapd is not a workaround either. The snap command talks to the daemon through the socket at /run/snapd.socket, so with the service stopped the command fails with a connection refused error, and the services that snaps provide stop being managed at all. Use a hold instead. It is the supported control, it is one command, and it reverses in one command.

Two things this schedule does not do. It never reads /etc/apt/apt.conf.d/50unattended-upgrades, so the unattended-upgrades policy you set for deb packages has no effect on snaps. And APT never upgrades a snap, so apt list --upgradable printing nothing is not evidence that the machine is current.

What a refresh does to a running service

A snap that ships a daemon is a set of systemd units that snapd generates and owns. When a refresh lands, snapd stops those units, points the snap's current symlink at the new revision, and starts them again. The gap is usually seconds. It is still a real restart, so open connections drop and anything held in memory is gone.

Snapd has a feature called refresh awareness that postpones an update while an application is in use. It does not help a server. The snap documentation states plainly that service management is not affected, because services are stopped and started as part of the refresh process. Refresh awareness protects a desktop application somebody has open on screen, and nothing protects your daemon except a hold or a refresh window.

A base snap counts too. core22 and core24 are the runtime that other snaps execute against, so refreshing a base can restart the snaps built on it. This is why an unexplained restart at 03:40 is worth checking against snap changes before you go digging through application logs.

Which server packages arrive as snaps

Run snap list and read the output, because the answer depends on the image you deployed and on what you installed afterwards. On a plain Ubuntu Server the list is short: snapd itself, one or more core bases, and whatever you added.

Certbot is the one most server operators meet, because the EFF's own instructions install it from the store:

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot

That puts your TLS (transport layer security) renewal tool outside APT entirely. If you followed the Certbot and Let's Encrypt setup for nginx, the certbot snap on that host updates on snapd's schedule and nothing in your APT configuration governs it. Certbot ships no daemon, so a refresh restarts nothing. The exposure is different: the tool that runs unattended twice a day can change behaviour without you asking.

LXD and MicroK8s are the other common ones. Both are distributed as snaps, both run daemons, and both hold state that other things depend on, which makes them exactly the case where an unplanned refresh hurts. If snap list on your box shows only snapd and a base, snap refreshes still run, but nothing you serve depends on them, and the policy section at the end is all you need.

Hold snap updates on one snap, or on all of them

A hold tells snapd to leave a snap alone. It takes a duration or the word forever.

sudo snap refresh --hold=72h lxd
sudo snap refresh --hold=forever lxd
sudo snap refresh --unhold lxd

The command confirms what it did and prints the time the hold expires. Verify it independently with snap list, where a held snap shows held in the Notes column. Duration units are seconds, minutes and hours, written s, m and h. There is no day unit, so a week is 168h.

The scope rule is subtle and worth reading twice. A hold on a named snap blocks the scheduled refresh and a bare sudo snap refresh, but it does not block a targeted sudo snap refresh lxd. So the hold defends the snap against the scheduler and against your own broad command, while still letting you update it on purpose. A hold with no snap named applies to every snap and blocks the scheduled refresh only, which means a bare sudo snap refresh updates everything anyway. If you hold all snaps and then run snap refresh out of habit, you have undone the hold's entire purpose in one line.

There is an older route through system options, sudo snap set system refresh.hold="2026-11-01T02:00:00+00:00", which takes an RFC 3339 timestamp (a standard date and time format) and accepts a date at most 90 days ahead. snap refresh --hold=forever has no such limit and is the clearer tool. It needs snapd 2.58 or newer, which every supported Ubuntu release has.

A hold stops updates. It does not stop vulnerabilities, so anything you freeze belongs on a list you revisit, alongside a regular check for known CVEs on the software you run.

Set a refresh window so restarts land when you are awake

If you do not want to freeze a snap, move it. refresh.timer replaces the default four-times-a-day schedule with hours you choose.

sudo snap set system refresh.timer=mon,03:00-05:00
sudo snap set system refresh.timer=4:00-7:00,19:00-22:10
sudo snap get system refresh.timer
snap refresh --time

The first line allows refreshes only between 03:00 and 05:00 on Mondays. The second allows two windows every day. A weekday prefix is optional, and the documented syntax also supports forms like fri5,23:00-01:00 for the fifth Friday of the month. Check the result with snap refresh --time, which now prints your timer and the next scheduled attempt. To go back to the default, run sudo snap unset system refresh.timer.

Do not make the window tiny. Snapd needs a chance to run inside it, so a server that is powered down or unreachable during your only Monday slot simply does not refresh that week, and the snaps age. A window of two hours or more, on a day that comes round weekly, is a sane floor.

One related option exists and rarely applies to a VPS: sudo snap set system refresh.metered=hold pauses refreshes on a connection the system reports as metered. Server networks are not reported as metered, so do not use this as an update policy. Reset it with sudo snap set system refresh.metered=null.

How many revisions snapd keeps, and what they cost on disk

Every snap revision is a squashfs image, a compressed read-only filesystem file, stored under /var/lib/snapd/snaps/ and mounted as a loop device. Keeping old revisions is what makes an instant rollback possible, and it is charged to your disk.

refresh.retain sets how many revisions of each snap survive. The valid range is 2 to 20. Classic Ubuntu defaults to 2, and Ubuntu Core keeps 3. Revisions above the limit are removed after the next refresh, not the moment you lower the number.

sudo du -sh /var/lib/snapd/snaps
snap list --all
sudo snap get system refresh.retain
sudo snap set system refresh.retain=2
sudo snap remove lxd --revision=27948

snap list --all prints every revision on disk and marks the inactive ones disabled in the Notes column. Those are the copies you are paying for. Remove one by hand with snap remove --revision=, which deletes that revision only and leaves the active one running.

Two related consumers are worth knowing about on a small volume. Removing a snap creates an automatic snapshot of its data, kept for 31 days by default under /var/lib/snapd/snapshots; snap saved lists them and sudo snap forget <id> deletes one. And df -h on any snap host lists a /dev/loopN mount per revision, every one of them at 100 percent used. That is normal for a read-only squashfs and never means your disk is full. Check the real filesystem with df -h /. If space is the reason you are here, the snap directory is usually the second largest offender after container images, so pair this with reclaiming disk from unused Docker images and volumes.

Read snap changes to see what happened

Snapd records every operation as a change with an identifier, a status and a summary.

snap changes
snap tasks 41
sudo journalctl -u snapd --no-pager --since "1 day ago"

The columns are ID, Status, Spawn, Ready and Summary. A refresh started by the scheduler is summarised as Auto-refresh snap "lxd" when one snap moved, or as Auto-refresh 7 snaps when snapd batched several together. Status Done means it finished. Undone means snapd rolled the change back, usually because a task failed partway, and a service that refuses to start under the new revision is a common cause. That single word answers the stuck-revision question: the update was tried and reverted, so nothing about waiting longer will help.

snap tasks <ID> expands one change into its individual tasks and shows which one failed, with the error text snapd recorded. Compare the Ready timestamp against your monitoring. A service restart in the same minute as a completed auto-refresh is not a coincidence.

Revert a bad revision

When a refresh installs a revision that misbehaves, you do not have to wait for a fix upstream.

snap list --all lxd
sudo snap revert lxd
sudo snap revert lxd --revision=27948
sudo snap refresh --hold=forever lxd

snap revert switches back to the previously used revision, and --revision= picks a specific one. It works only while that older revision is still on disk, which is what refresh.retain decides, so a machine set to retain 2 has exactly one step back available.

A revert rolls back data as well as code. Each revision has its own data directory under /var/snap/<name>/<revision>, and writes made while the new revision was running stay in the new revision's directory. For a stateful snap such as a container manager or anything holding a database, treat a revert as a restore to the moment the refresh happened, and take a copy of the current data directory first.

Then hold the snap, as in the last line above. Without a hold, the next scheduled refresh reinstalls the same broken revision and you do this all over again.

Put snap updates and APT updates in one policy

A server running snaps has two updaters with separate schedules, separate configuration and separate logs. Treating snap as an exception is what produces surprise restarts. Write down four decisions instead.

  1. Which snaps run daemons that matter to you. Those get a hold, or a refresh window you chose.
  2. When your maintenance window is. Point refresh.timer and your unattended-upgrades schedule at the same hours, so one window covers both.
  3. How you learn that something changed. snap changes belongs next to apt list --upgradable in your routine, which is the same routine as the monthly Linux server maintenance checklist.
  4. How much disk you are spending on rollback. refresh.retain and du -sh /var/lib/snapd/snaps give you the number.

The two updaters also differ in what a big jump means. APT changes arrive gradually within a release and in bulk when an Ubuntu point release lands, while a snap can cross a major version the moment you change its track. Both belong in the same window and the same log review. Snap is not an exception to your update policy. It is the half of the policy that runs without asking.

FAQ

Why is my snap stuck on an old revision?

Check four things in order. Run snap list and look for held in the Notes column, which means a refresh hold is active. Look at the Tracking column, because a snap following 5.21/stable receives fixes inside 5.21 and never moves to 6.x. Run snap changes and look for Undone, which means the refresh was tried and rolled back. If all three look normal, the store may be rolling the revision out progressively to a share of machines, and yours has not been selected yet.

How do I stop a snap from updating on its own?

Run sudo snap refresh --hold=forever <snap> for an indefinite hold, or sudo snap refresh --hold=72h <snap> for a temporary one. Duration units are s, m and h, so a week is 168h. Remove it with sudo snap refresh --unhold <snap>. Do not try to stop snapd instead: the snap command speaks to the daemon over /run/snapd.socket, so a stopped snapd means the command fails with a connection refused error and your snap services are no longer managed.

Does unattended-upgrades update snaps?

No. unattended-upgrades drives APT, and APT has no knowledge of snaps. Snap updates come from snapd, which contacts the Snap Store four times a day by default on a schedule stored in its own state. apt list --upgradable showing an empty list tells you nothing about the snaps on the machine. Use snap refresh --list for that.

Will a snap refresh restart my service?

Yes. Snapd stops the systemd units it generated for the snap, switches to the new revision, and starts them again, so a refresh is a short restart. Refresh awareness, the feature that defers updates for applications in use, explicitly does not cover services, because services are stopped and started as part of the refresh. If a restart at an unplanned hour is unacceptable, hold the snap or set refresh.timer to a window you control.

How do I reclaim the disk that old snap revisions use?

Run snap list --all to see every revision, with the inactive ones marked disabled, and sudo du -sh /var/lib/snapd/snaps for the total. Lower the retention with sudo snap set system refresh.retain=2, the minimum allowed value, and remove a specific leftover with sudo snap remove <snap> --revision=<n>. Ignore the /dev/loopN entries that df -h reports at 100 percent used, since a read-only squashfs mount is always full by definition.