If you need remote GUI access to a headless Raspberry Pi, the TeamViewer Host package (specifically the arm64 build) is the correct choice for the Raspberry Pi 5. Unlike the full TeamViewer client, the Host variant runs as a system daemon, survives reboots, and allows unattended access without a local monitor or keyboard. However, deploying it on the latest 64-bit Raspberry Pi OS (Bookworm) introduces new hurdles—primarily around the Wayland display server and power management—that crash the daemon silently.
This guide provides a bench-tested installation sequence, a Python-based GPIO hardware watchdog to auto-recover crashed daemons, and exact debugging steps for the most common connection errors.
Hardware Spec Sheet & Parts List
TeamViewer's background daemon and screen-capture hooks are surprisingly resource-intensive. Running this on an underpowered Pi 4 or a Pi 5 with a generic phone charger will result in random daemon crashes due to voltage droop. Use this exact hardware baseline for a stable deployment.
| Component | Exact Variant / Specification | Why It Matters |
|---|---|---|
| Microcontroller | Raspberry Pi 5 (8GB RAM) | 4GB works, but 8GB prevents OOM kills when the TeamViewer daemon and GUI apps run concurrently. |
| Power Supply | Official 27W USB-C PD Power Supply | Pi 5 requires 5V/5A. Standard 5V/3A supplies cause brownouts that kill the teamviewerd service. |
| Cooling | Active Cooler (Official) | Screen encoding spikes CPU temp; thermal throttling causes network timeouts. |
| Status LED | 5mm Green LED + 330Ω Resistor | Visual confirmation of daemon health when headless. |
| Reset Switch | 6x6mm Tactile Pushbutton | Hardware trigger to restart the daemon if SSH is also locked out. |
GPIO Pin Mapping for Hardware Watchdog
To ensure you can recover the Pi if both TeamViewer and SSH fail, we wire a physical status LED and a reset button. This uses the gpiozero library, which is fully compatible with the Pi 5's new RP1 I/O controller.
| Component | BCM GPIO Pin | Physical Pin (40-pin Header) | Wiring Notes |
|---|---|---|---|
| Status LED (Anode) | GPIO 17 | Pin 11 | Connect via 330Ω resistor to LED anode. |
| Status LED (Cathode) | GND | Pin 9 | Direct to ground. |
| Reset Button (Leg 1) | GPIO 27 | Pin 13 | Internal pull-up enabled in code; no external resistor needed. |
| Reset Button (Leg 2) | GND | Pin 14 | Direct to ground. |
Step-by-Step Headless Installation
The standard apt install teamviewer command often pulls the wrong architecture or the full client instead of the Host. Follow these exact terminal commands on your Pi 5.
- Update and install dependencies:
sudo apt update && sudo apt install -y libminizip1 libxtst6 - Download the official Host package:
Navigate to the TeamViewer Linux download page and copy the link for the 'Host' arm64 .deb file, or use wget:
wget https://download.teamviewer.com/download/linux/teamviewer-host_arm64.deb - Install the package:
sudo apt install -y ./teamviewer-host_arm64.deb - Assign the device to your account (Headless):
Since you have no GUI to log in, use the CLI setup tool:
sudo teamviewer setup
Note: This will prompt for your TeamViewer email and password in the terminal. - Enable the daemon on boot:
sudo systemctl enable teamviewerd && sudo systemctl start teamviewerd
teamviewer assignment command with an API token instead of setup to avoid typing credentials into the terminal. Refer to the Raspberry Pi OS configuration docs for automating this via cloud-init.
Python Watchdog Script (Auto-Recovery)
Headless daemons occasionally hang due to network state changes or Wayland compositor crashes. This Python script targets the Raspberry Pi 5 (Bookworm 64-bit). It polls the teamviewerd systemd service every 30 seconds. If it detects a failure, it restarts the service and blinks the LED. Pressing the physical button forces an immediate restart.
#!/usr/bin/env python3
import subprocess
import time
import logging
from gpiozero import LED, Button
from signal import pause
# --- PIN DEFINITIONS (Pi 5 40-pin header) ---
LED_PIN = 17 # BCM 17 (Physical Pin 11)
BTN_PIN = 27 # BCM 27 (Physical Pin 13)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
status_led = LED(LED_PIN)
reset_btn = Button(BTN_PIN, pull_up=True, bounce_time=0.2)
def check_daemon_status():
"""Returns True if teamviewerd is active, False otherwise."""
try:
result = subprocess.run(
['systemctl', 'is-active', 'teamviewerd'],
capture_output=True, text=True, check=False
)
return result.stdout.strip() == 'active'
except Exception as e:
logging.error(f'Systemctl execution failed: {e}')
return False
def restart_daemon():
"""Attempts to restart the teamviewerd service."""
logging.warning('Daemon inactive. Attempting restart...')
status_led.blink(on_time=0.2, off_time=0.2) # Fast blink during restart
try:
subprocess.run(['sudo', 'systemctl', 'restart', 'teamviewerd'], check=True)
time.sleep(3) # Allow service time to initialize
if check_daemon_status():
logging.info('Daemon successfully restarted.')
status_led.on()
else:
logging.error('Restart command succeeded but daemon is still inactive.')
status_led.blink(on_time=1, off_time=1) # Slow blink for hard failure
except subprocess.CalledProcessError as e:
logging.error(f'Failed to restart daemon: {e}')
status_led.blink(on_time=1, off_time=1)
# Hardware button callback
reset_btn.when_pressed = restart_daemon
if __name__ == '__main__':
logging.info('TeamViewer Hardware Watchdog started.')
status_led.on()
try:
while True:
if not check_daemon_status():
restart_daemon()
else:
status_led.on() # Solid ON means healthy
time.sleep(30) # Poll every 30 seconds
except KeyboardInterrupt:
logging.info('Watchdog terminated by user.')
status_led.off()
Debugging: 'Not ready. Please check your connection.'
The most notorious error when running teamviewer --info on a headless Pi is this exact string:
TeamViewer ID: Not ready. Please check your connection.
This is a generic catch-all error from the TeamViewer binary, but on the Pi 5, it almost always stems from one of three specific root causes.
The First Three Things to Check
- Verify Systemd Status: Run
sudo systemctl status teamviewerd. If it showsinactive (dead)orfailed, the daemon crashed on boot. Checkjournalctl -u teamviewerd -efor OOM (Out of Memory) kills. - Check Wayland vs. X11: Raspberry Pi OS Bookworm defaults to Wayland. TeamViewer's screen capture hooks rely on X11 extensions (XTest/MIT-SHM). If Wayland is active, TeamViewer cannot hook the display and will refuse to fully initialize the connection ID.
- Measure the 5V Rail: Run
vcgencmd get_throttled. If it returns0x50005or similar, you are experiencing under-voltage. The Wi-Fi chip and CPU spike during TeamViewer handshake, tripping the brownout detector and killing the daemon.
Ranked Causes & Fixes
| Rank | Root Cause | Exact Fix |
|---|---|---|
| 1 | Wayland Display Server Blocking Hooks | Run sudo raspi-config -> Advanced Options -> Wayland -> Select X11. Reboot. |
| 2 | DNS Resolution Failure for UDP Handshake | Flush DNS and restart networking: sudo resolvectl flush-caches && sudo systemctl restart NetworkManager |
| 3 | Missing Headless Dummy Display | If no HDMI is plugged in, the Pi disables the GPU compositor. Buy a $5 'HDMI Dummy Plug' or configure a virtual display in /boot/firmware/config.txt. |
Extending vs. Simplifying Your Remote Access
Before locking in your deployment, evaluate if TeamViewer is actually the right tool for your specific project constraints.
How to Simplify: If you only need terminal access and file transfers, drop TeamViewer entirely. Use Tailscale combined with SSH. Tailscale creates a zero-config mesh VPN, and SSH uses a fraction of the CPU/RAM overhead. If you absolutely need a GUI but want to avoid TeamViewer's aggressive 'commercial use suspected' timeouts, use RustDesk (open-source, self-hostable, and Wayland-compatible).
How to Extend: If this Pi is in a remote field location (e.g., a weather station or greenhouse), software watchdogs aren't enough. Extend the Python script above by adding an opto-isolated relay module on GPIO 22. Wire the relay in series with the Pi's 5V power input. If the Python script detects that systemctl restart fails three times in a row, it triggers the relay to physically cut and restore power, ensuring a hard hardware reset.
Frequently Asked Questions
Does TeamViewer for Raspberry Pi work on headless setups without a dummy plug?
Out of the box, no. If the Raspberry Pi boots without an HDMI monitor attached, the GPU display compositor does not initialize. TeamViewer requires a compositor to capture the screen. You must either plug in an HDMI dummy plug (a $5 dongle that emulates a 1080p monitor) or force a virtual display by adding hdmi_force_hotplug=1 and hdmi_group=2 to your /boot/firmware/config.txt file.
Why is TeamViewer for Raspberry Pi showing a black screen on Bookworm?
This is the Wayland conflict mentioned in the debugging section. Raspberry Pi OS Bookworm uses Wayland by default, which isolates applications from reading each other's memory buffers for security. TeamViewer's legacy Linux client cannot capture the screen under Wayland. Switching to the X11 windowing system via raspi-config resolves the black screen issue immediately.
Is TeamViewer for Raspberry Pi free for commercial use?
No. TeamViewer's licensing model applies to the Host package just as it does to the desktop client. If their heuristic algorithms detect you connecting to the Pi from a corporate network or during standard business hours frequently, they will flag the device for 'commercial use' and limit your sessions to 5 minutes. For commercial IoT deployments, you must purchase a TeamViewer IoT license or switch to an open-source alternative like RustDesk.
How do I completely uninstall TeamViewer from my Raspberry Pi?
Simply running sudo apt remove teamviewer-host leaves behind configuration files, repository lists, and systemd hooks. To completely purge it, run:
sudo apt purge teamviewer-host
sudo rm /etc/apt/sources.list.d/teamviewer.list
sudo systemctl daemon-reload
This ensures no background services attempt to phone home on the next reboot.






