VNC Disconnects and Freezes: Dropped, Dead or Just Stuck?

Before you change anything, work out which of three things happened. A viewer that closes lost its connection. A viewer that stays open on a still picture is connected but getting no screen updates. A server that's gone took the session with it. Most drops come from a second viewer taking over the session, an idle path through NAT or an SSH tunnel going stale, a server timer, or a server that died; a frozen picture points at the update path or a connection waiting for someone to approve it.

Don't blame a timeout first. TigerVNC's idle and session-length timers, -IdleTimeout, -MaxIdleTime, -MaxConnectionTime and -MaxDisconnectionTime, all default to 0, which means off, so a timer only explains your drop once you've read a nonzero value from the running server. RealVNC Server is the odd one out: its IdleTimeout is an hour out of the box.

Dropped, dead or stuck: tell them apart first

Between you and the remote desktop sit the viewer, the network path (router NAT, firewall, VPN or SSH tunnel), the VNC server (Xtigervnc on display :1, listening on port 5901, or x11vnc sharing display :0) and the desktop session the server runs. Each fails in its own way:

  • The path breaks: your viewer closes or reports a lost connection, and the server keeps running.
  • The server dies: your viewer closes and nothing listens on 5901 any more.
  • The server or desktop stalls: your viewer stays open on a static image, and the host still answers SSH.

Note three things before you reconnect or restart, because a restart wipes out the difference. Did the viewer close or report a lost connection, or is it still open? Does the clock on the remote desktop still move? Can you still SSH in? Also note what came right before it: idle time, a second viewer connecting, the first screen painting, or one particular thing you did on the desktop.

The commands below are for TigerVNC 1.13.1 on Ubuntu 24.04, with display :1 on port 5901 reached through an SSH tunnel. Other installs change names and paths, listed at the end.

Match the symptom to a cause

Most likely first:

symptom cause check fix
Your viewer closes the moment someone else connects A non-shared connection, and Xtigervnc drops existing clients by default (DisconnectClients is on) Ask who else connected at the moment of the drop Connect every viewer with -Shared, or start the server with -AlwaysShared
Drops only after a quiet spell, never while you work, often through NAT, VPN or an SSH tunnel Connection state in a NAT device or firewall expired The SSH tunnel dies at the same moment Keepalives: ServerAliveInterval on the tunnel, -ping on x11vnc
RealVNC Server drops you after an hour without input RealVNC Server’s IdleTimeout defaults to 3600 seconds It happens 60 minutes after your last keystroke or click Set IdleTimeout=0 in its config
Drops after the same idle time, server still running Xtigervnc IdleTimeout is nonzero tigervncconfig -display :1 -get IdleTimeout Set it back to 0
Server gone after a fixed time connected or inactive MaxConnectionTime or MaxIdleTime is nonzero; both terminate the server, not just the connection tigervncserver -list no longer shows :1; -get shows the value Set the timer back to 0 and restart the session
Server gone at random, often when a heavy application starts Xtigervnc or the desktop was killed for memory or crashed journalctl -k for Killed process, then the session log Give the session more memory, or fix the application the log names
x11vnc: the first viewer worked, the next one is refused x11vnc exits after the first viewer disconnects (-once is the default) No x11vnc process left on the server Start it with -forever
x11vnc: drop while the first screen paints over a slow link The 20 second -readtimeout ran out The drop comes before the first full screen Raise -readtimeout
Connects, then rejected about 10 seconds later QueryConnect is on and nobody at the desktop accepted tigervncconfig -display :1 -get QueryConnect Turn QueryConnect off for an unattended session
Viewer open, picture static, cursor moves, SSH works The update or encoding path stalled Fast redraws (switching tabs, dragging windows) reproduce it Reconnect, then force a different encoding

The path rows are the ones you can't see from the server. Stateful NAT, firewalls and load balancers expire a connection's session context once no packet has crossed it for a while, and every packet after that is dropped. A VPN with a smaller MTU adds its own drops for packets bigger than the link carries.

Check the server before you touch the network

A laptop, a monitor with one lit status indicator, and a small server block joined by connector lines on a dark ground.

These checks leave the session alone, so run them first. They stop you from changing a timeout when the viewer actually stayed connected, or chasing the network when the server simply exited.

  1. Is the server still running and listening? From an SSH shell on the server, as the session user:

    check the server before you touch the network · bash
    tigervncserver -list
    ss -tlnp | grep ':5901'

    If :1 is missing from the -list output, Xtigervnc exited and your viewer had nothing left to talk to. While the server is up, ss prints a LISTEN line on 127.0.0.1:5901 or 0.0.0.0:5901; no line means the same thing, seen from the network side. A listening port only rules out a dead server. It doesn't prove the path works.

  2. What do the logs say around the failure time?

    check the server before you touch the network · bash
    tail -n 50 ~/.vnc/*:1.log
    sudo journalctl -u tigervncserver@:1.service --since "15 min ago"
    sudo journalctl -k | grep -i 'killed process'

    The session log collects output from the server and from every application the session started, so a crashing desktop shows up there. The journalctl -u line only has something to show if you run the session from the tigervncserver@:<display>.service unit. Both journalctl lines read the system journal, which only root and members of adm or systemd-journal can open, hence the sudo. With -k you get kernel messages only, and when the OOM killer takes out Xtigervnc or the desktop it logs Killed process <pid> (<name>).

  3. Which timers is the running server actually using?

    check the server before you touch the network · bash
    tigervncconfig -display :1 -get IdleTimeout
    tigervncconfig -display :1 -get MaxConnectionTime
    tigervncconfig -display :1 -get MaxIdleTime
    tigervncconfig -display :1 -get QueryConnect

    tigervncconfig -get prints the value in force right now, whichever file or flag set it. Anything other than 0 on the first three is a live timer.

  4. Only if the path is still in question, capture it. Start a capture on both ends before you reproduce the drop; a two-sided trace shows where the packets stop:

    check the server before you touch the network · bash
    sudo tcpdump -ni <interface> -w vnc-server.pcap port 5901

    Through an SSH tunnel, capture port 22 on both ends instead, because port 5901 on the server only carries the tunnel's loopback traffic. -w saves raw packets you can open in Wireshark.

Fix the cause you found

Change a server setting only when its live value matches the failure.

Someone else connected and you got kicked

Unless a viewer asks for a shared session, Xtigervnc drops the clients already connected when it arrives: -Shared is off by default in the viewer and DisconnectClients is on in the server. When several people use the same desktop, have every viewer connect with xtigervncviewer -Shared localhost:1, or start the server with -AlwaysShared.

The tunnel or NAT went quiet

Keep traffic on the path. Add a keepalive to the tunnel, then point the viewer at the tunnel's local end from a second terminal:

the tunnel or nat went quiet · bash
ssh -o ServerAliveInterval=30 -L 5901:localhost:5901 <user>@<server-host>
xtigervncviewer localhost:1

With ServerAliveInterval=30 and the default ServerAliveCountMax of 3, ssh sends a probe after 30 seconds of silence, which keeps an idle tunnel's NAT entry alive. If the path really is gone, ssh gives up after about 90 seconds with no answer and prints Timeout, server <server-host> not responding. instead of hanging. The -L forward maps your local port 5901 to the server's 5901, and localhost:1 is display 1, so port 5901. For x11vnc on a direct connection, -ping 30 does the same job by sending a tiny framebuffer update every 30 seconds.

A TigerVNC timer is set

Find where the nonzero value comes from, then restart the session with the timer off:

a tigervnc timer is set · bash
grep -i -E 'IdleTimeout|MaxConnectionTime|MaxIdleTime' /etc/tigervnc/vncserver-config-* ~/.vnc/tigervnc.conf ~/.vnc/config
tigervncserver -kill :1
tigervncserver :1 -IdleTimeout 0

The wrapper passes options it doesn't know to Xtigervnc, so -IdleTimeout 0 reaches the server. Watch for /etc/tigervnc/vncserver-config-mandatory: a value there overrides the command line, so if that's where grep found it, fix it in that file. If the systemd unit runs your session, remove the value from the file grep found and run sudo systemctl restart tigervncserver@:1.service instead. MaxConnectionTime and MaxIdleTime work the same way. Afterwards, tigervncconfig -display :1 -get IdleTimeout should print 0, and the next session should stay up past the old limit.

RealVNC Server cuts you off after an hour

In Service Mode the parameter goes in /root/.vnc/config.d/vncserver-x11, and 0 never disconnects idle users:

realvnc server cuts you off after an hour · bash
echo 'IdleTimeout=0' | sudo tee -a /root/.vnc/config.d/vncserver-x11
sudo systemctl restart vncserver-x11-serviced

x11vnc exits after the first viewer

x11vnc exits after the first viewer · bash
x11vnc -display :0 -rfbauth ~/.vnc/passwd -forever -o ~/x11vnc.log

-once is the default, so without -forever x11vnc exits when the first viewer leaves. Add -nevershared as well and it also clears hung TCP connections that never go away, because each new viewer replaces the old one. After a disconnect, ss -tlnp | grep x11vnc should still show it listening.

Keep -rfbauth on the line when you restart it. x11vnc -storepasswd writes that file to ~/.vnc/passwd, and without a password option x11vnc lets in anyone who reaches the port and only prints a warning. Add -localhost when you come in through the SSH tunnel.

x11vnc drops while the first screen paints

x11vnc drops while the first screen paints · bash
x11vnc -display :0 -rfbauth ~/.vnc/passwd -forever -readtimeout 60 -o ~/x11vnc.log

-readtimeout defaults to 20 seconds, and a first screen that takes longer than that to paint over a slow link gets the connection dropped. With 60, the next connection should finish painting.

Rejected after 10 seconds, or a picture that stopped moving

Nobody is there to accept the connection

With QueryConnect on, Xtigervnc asks the person at the desktop to accept each connection, needs tigervncconfig running on that desktop to show the dialog, and rejects the connection when QueryConnectTimeout runs out, 10 seconds by default. On an unattended session nobody answers. Remove QueryConnect from wherever it's set (the grep in the timer fix finds it if you add it to the pattern) and restart the session, or have someone at the desktop accept.

The viewer is open but the picture froze

Reconnect first, and only that. Closing and reopening the viewer rejoins the running session, and you need to know whether that alone brings the desktop back before you change anything else. If the freeze returns, pin the encoding:

the viewer is open but the picture froze · bash
xtigervncviewer -AutoSelect=0 -PreferredEncoding=ZRLE localhost:1

By default the viewer tests the connection speed and picks the encoding and pixel format itself, and it can adjust Tight's JPEG quality on the fly too. With -AutoSelect=0 and ZRLE you get one fixed encoding with no JPEG step and nothing switching underneath you. Repeat whatever reproduced the stall, such as fast tab switching. If it no longer freezes, the encoder path was the problem. One openSUSE Leap 15.1 user reported no further freezes after selecting ZRLE in place of the default Tight encoding, with the viewer's JPEG setting at quality 8.

When it keeps coming back

A labeled diagram comparing connection-ended failures against static-screen failures, each side listing four causes with distinct markers.

If the symptom returns after a fix that matched its cause, or your notes can't tell a server exit from a viewer-only stall, stop changing settings and take it to the implementation's issue tracker or support channel. Bring:

  • Implementation and version: server, viewer and OS release. tigervncserver -version prints the server's.

  • Failure time and action: when the updates stopped or the connection ended, and what reliably came before it.

  • Session and viewer logs: the server log from ~/.vnc/, plus a verbose viewer log captured while you reproduce it. -Log writes to stderr, so redirect it with 2>:

    when it keeps coming back · bash
    xtigervncviewer -Log '*:stderr:100' localhost:1 2> viewer.log

  • Service events: the journalctl -u tigervncserver@:1.service output for the same minutes.

Other installs: what changes

Ubuntu 24.04 ships TigerVNC 1.13.1. Elsewhere, only these change:

Put the fix where it survives the next session. A keepalive belongs in a Host block in ~/.ssh/config for that server, not on one command line you'll forget to retype, and a nonzero timer has to come out of the file grep found it in, or it's back on the next start without the -IdleTimeout 0 flag.

FAQs

Does TigerVNC close a disconnected session by default while no viewer is attached?

No. MaxDisconnectionTime defaults to 0, so the server keeps running with no viewer attached until someone sets it. tigervncconfig -display :1 -get MaxDisconnectionTime shows the live value.

Can I set the keepalive once on the server instead of on every tunnel?

Yes, in sshd. Put ClientAliveInterval 30 in a file of its own such as /etc/ssh/sshd_config.d/keepalive.conf and run sudo systemctl reload ssh. sshd then sends a probe through the encrypted channel after 30 seconds without data from the client, which keeps every user's tunnel busy enough for the NAT entry to stay. With ClientAliveCountMax at its default of 3, it also drops a client that stops answering for about 90 seconds.

How do I get a TigerVNC viewer log on Windows, where there's no stderr to redirect?

Send it to a file instead: vncviewer.exe -Log *:file:100 <server-host>:1. Releases up to 1.16 write that log to C:\temp\vncviewer.log, and the viewer won't create the folder, so make C:\temp first. Copy the log off before you start the viewer again: each run renames the previous one to vncviewer.log.bak and starts a fresh file.