WSL2 Desktop Troubleshooting: Black Screen, XRDP & Display Fixes

WSL2 Desktop Troubleshooting: Black Screen, XRDP & Display Fixes architecture diagram

Things don't always work on the first try. This guide covers the most common WSL2 GUI problems and how to fix them, organised by whether you're using WSLg (individual apps) or XRDP (full desktop).

General Issues

These problems affect both WSLg and XRDP setups.

The ACPI Problem

If you've installed a full desktop package like ubuntu-desktop, you've probably seen this:

Starting acpid: failed Could not open /proc/acpi/event

This isn't a bug in your setup. It's a fundamental mismatch between what desktop packages expect and what WSL2 provides.

Why It Happens

Desktop packages pull in services designed for real hardware:

ServicePurposeWhy It Fails in WSL2
acpidPower events (lid close, power button)No physical hardware
thermaldCPU thermal throttlingNo thermal sensors
upowerBattery statusNo battery
bluetoothBluetooth stackNo Bluetooth adapter
ModemManagerMobile broadbandNo modem

WSL2 runs in a lightweight VM. There's no lid to close, no battery to monitor.

wsl2-gui-part3-troubleshooting/wsl2-services diagram
Click to expand
693 × 842px

The systemd Loop Problem

With systemd enabled, acpid can cause an infinite loop:

  1. acpid.service tries to start
  2. Condition check fails: ConditionVirtualization=!container failed
  3. acpid.path detects the failure and triggers a restart
  4. Back to step 1

This loop can consume CPU and fill your logs. In severe cases, it can destabilise systemd itself.

The Fix: Mask These Services

Masking tells systemd to never start a service, even if something depends on it:

bash
sudo systemctl mask acpid.service acpid.socket acpid.path sudo systemctl mask thermald.service sudo systemctl mask upower.service sudo systemctl mask bluetooth.service sudo systemctl mask ModemManager.service

This is better than removing packages because:

  • Dependencies won't try to reinstall them
  • You can unmask later if needed

To unmask:

bash
sudo systemctl unmask acpid.service acpid.socket acpid.path

Prevent During Installation

If you haven't installed your desktop yet:

bash
sudo apt install --no-install-recommends ubuntu-desktop-minimal -y

The --no-install-recommends flag skips optional packages like hardware services.

Systemd Issues

Services Won't Start

First verify systemd is running:

bash
cat /proc/1/comm

If it shows init, enable systemd:

bash
sudo tee -a /etc/wsl.conf << 'EOF' [boot] systemd=true EOF

Then:

powershell
wsl --shutdown

Service Starts But Immediately Stops

Check the logs:

bash
journalctl -u xrdp --no-pager | tail -50 journalctl -u xrdp-sesman --no-pager | tail -50

Common causes:

  • Missing dependencies
  • Port already in use
  • Permission issues

Memory Management

Running a desktop uses memory. Control it with .wslconfig.

Create C:\Users\YourName\.wslconfig:

ini
[wsl2] memory=8GB processors=4 swap=2GB

Apply changes:

powershell
wsl --shutdown

Monitor Usage

Inside WSL:

bash
free -h

From Windows, check Task Manager for "Vmmem".

WSL Shutting Down During RDP Session

If your distro shuts down while you're connected via RDP, WSL's idle timeout is the cause. WSL doesn't recognize RDP connections as "active usage"—it only tracks terminal sessions.

Symptoms

  • Desktop freezes or disconnects after ~15 seconds of inactivity
  • Distro shows as stopped in wsl -l -v
  • Works fine when a terminal window is also open

Understanding WSL's Two Timeouts

WSL has two separate idle timeouts—you need to disable both:

SettingSectionDefaultWhat It Controls
instanceIdleTimeout[general]15 secondsHow long an instance stays alive after all user processes exit
vmIdleTimeout[wsl2]60 secondsHow long the VM stays alive after all instances terminate

When you connect via RDP without a terminal, WSL considers the instance "idle" (no tracked processes). After 15 seconds, it terminates the instance. Setting only vmIdleTimeout=-1 keeps the VM running but doesn't prevent instance termination.

The Fix: Disable Both Timeouts

Create or edit C:\Users\YourName\.wslconfig:

ini
[general] instanceIdleTimeout=-1 [wsl2] vmIdleTimeout=-1

Apply the change:

powershell
wsl --shutdown

The -1 value disables timeouts completely. Alternatively, set a long timeout in milliseconds (e.g., 86400000 for 24 hours).

Note: instanceIdleTimeout was added in WSL 2.4.4. If you're on an older version, update WSL: wsl --update

Alternative: Keep a Terminal Open

Keep a Windows Terminal tab open to the distro while using RDP. This counts as an active session and prevents shutdown.

Network Managers Breaking WSL Mirrored Networking

If you're using networkingMode=mirrored in your .wslconfig and installed a desktop environment, you may find networking suddenly stops working—not just in the distro with the desktop, but in all your WSL distros.

Symptoms

bash
$ ip -br addr lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP # <-- No IP address! eth1 UP eth2 UP $ ping 8.8.8.8 ping: connect: Network is unreachable

The interfaces are UP but have no IP addresses assigned, and the routing table is empty.

The Culprit: ConnMan and Friends

Desktop environments often install network management daemons:

DesktopNetwork ManagerProblem
LXQtConnManTries to manage interfaces, conflicts with WSL
GNOMENetworkManagerCan interfere with mirrored networking
KDENetworkManagerSame issue

These services assume they're running on real hardware and try to configure networking themselves, which breaks WSL's mirrored networking mode.

How to Diagnose

Check what network services are running:

bash
systemctl list-units --type=service --state=running | grep -iE 'network|connman|nm'

If you see connman.service or NetworkManager.service, that's likely your problem.

The Cross-Distro Test

To confirm, try this:

  1. wsl --shutdown from Windows
  2. Start a minimal distro (one without a desktop): wsl -d <other-distro>
  3. Check networking—it should work
  4. Now start your desktop distro: wsl -d <desktop-distro>
  5. Go back to the minimal distro and check networking again

If networking breaks in the minimal distro after starting the desktop distro, you've confirmed the issue.

The Fix

Disable and mask the offending service:

bash
# For ConnMan (LXQt, Enlightenment) sudo systemctl disable --now connman sudo systemctl mask connman # For NetworkManager (GNOME, KDE) sudo systemctl disable --now NetworkManager sudo systemctl mask NetworkManager

After masking, restart WSL:

powershell
wsl --shutdown

Networking should now work reliably across all distros.

Optimising Services for WSL Performance

Desktop environments install many services designed for physical hardware. In WSL, these waste resources and can cause slowdowns or failures.

Services to Disable

Run this to disable unnecessary services:

bash
sudo systemctl disable --now \ sddm \ snapd snapd.socket \ avahi-daemon avahi-daemon.socket \ bluetooth \ ofono dundee \ wpa_supplicant \ switcheroo-control \ unattended-upgrades \ preload \ udisks2 \ upower # Mask them to prevent reactivation sudo systemctl mask \ sddm \ snapd snapd.socket \ avahi-daemon avahi-daemon.socket \ bluetooth \ ofono dundee \ wpa_supplicant \ switcheroo-control

Why Each Service Is Unnecessary

ServicePurposeWhy Disable in WSL
sddm/gdm/lightdmDisplay managerUsing XRDP instead
snapdSnap packagesSlow, snaps have X auth issues
avahi-daemonmDNS/BonjourCan conflict with WSL networking
bluetoothBluetooth stackNo Bluetooth in WSL
ofono/dundeeTelephony/DUNNo modem in WSL
wpa_supplicantWiFi managementNo WiFi in WSL
switcheroo-controlGPU switchingNot applicable
unattended-upgradesAuto updatesCan cause random slowdowns
preloadReadahead daemonCan cause issues in VMs
udisks2Disk managementNot needed for WSL mounts
upowerPower managementNo battery in WSL

Checking the Result

After disabling, check what's still running:

bash
systemctl list-units --type=service --state=running | wc -l

A well-optimised WSL desktop distro should have around 15-20 running services, not 30+.

Check system load:

bash
uptime free -h

You should see low load averages (under 0.5) and reasonable memory usage.

Virtual Disks Showing in File Manager

When running a desktop environment, you may see devices like /dev/sda, /dev/sdb, etc. in your file manager's sidebar. These are WSL2's virtual block devices—not your Windows drives.

What These Devices Are

DeviceWhat It Is
/dev/sdaWSL2's root filesystem (ext4 virtual disk)
/dev/sdb, /dev/sdc, etc.Windows drives mounted as virtual block devices

Your actual Windows files are at /mnt/c, /mnt/d, etc.—not these block devices.

Clicking on /dev/sdX devices prompts for a password because the file manager tries to mount them as removable drives, which doesn't work in WSL.

Hide in File Manager Settings

Thunar (XFCE): Edit → Preferences → Side Pane → uncheck device options, or right-click device → "Unmount and Eject"

Caja (MATE): Edit → Preferences → Sidebar → adjust "Show" options

Dolphin (KDE): Right-click sidebar → "Hide Section" or configure in Places panel settings

Access Windows Files Correctly

Your Windows drives are at:

bash
/mnt/c # C: drive /mnt/d # D: drive # etc.

Add bookmarks to these paths in your file manager for easy access.

XRDP Troubleshooting

Issues specific to running a full Linux desktop via XRDP.

Black Screen After Login

The most common XRDP problem. You connect, enter credentials, then... nothing but black.

Cause 1: Missing or Wrong .xsession

XRDP doesn't know which desktop to start:

bash
cat ~/.xsession

Should contain your desktop's start command. Create or fix it:

bash
# For XFCE echo "startxfce4" > ~/.xsession # For MATE echo "mate-session" > ~/.xsession # For LXQt echo "startlxqt" > ~/.xsession

Cause 2: startwm.sh Conflicts

XRDP's default startup script can conflict with your session configuration. Edit it:

bash
sudo nano /etc/xrdp/startwm.sh

Comment out these lines near the bottom:

bash
# test -x /etc/X11/Xsession && exec /etc/X11/Xsession # exec /bin/sh /etc/X11/Xsession

Add your desktop command:

bash
startxfce4

Cause 3: GNOME Needs Extra Configuration

GNOME requires environment variables. See the GNOME Desktop Not Working section below.

Cause 4: Same User Logged In Elsewhere

If you're logged in via WSLg and try to connect via XRDP with the same user, you may get a black screen. Log out of WSLg first, or use a different user for XRDP.

Cause 5: D-Bus Not Running

Desktop environments need D-Bus:

bash
sudo service dbus status

If not running:

bash
sudo service dbus start

With systemd:

bash
sudo systemctl start dbus

Cause 6: WSLg Environment Variables Conflict

This is a subtle one. If WSLg is enabled, it sets environment variables that leak into your XRDP session, causing apps to try connecting to the wrong display server.

How to diagnose:

Check your session errors after a failed login:

bash
cat ~/.xsession-errors

If you see errors like:

xfwm4: cannot open display: wayland-0

Or anything referencing wayland-0 when you're trying to run an X11 session, WSLg is interfering.

What's happening:

WSLg sets these variables system-wide:

VariableWSLg ValueXRDP Expects
DISPLAY:0:10 (or similar)
WAYLAND_DISPLAYwayland-0(not set)

When XRDP starts your session, these WSLg variables persist and confuse X11 applications—they try to connect to Wayland or the wrong X display.

Why unsetting in scripts doesn't reliably work:

You might think adding unset WAYLAND_DISPLAY to ~/.xsession or /etc/xrdp/startwm.sh would fix this. Sometimes it does, but the variables can be re-set by profile scripts or the compositor itself before your desktop fully starts.

The reliable fix:

Disable WSLg entirely if you're using XRDP for your desktop. Create or edit C:\Users\YourName\.wslconfig:

ini
[wsl2] guiApplications=false

Then restart WSL:

powershell
wsl --shutdown

Now reconnect via XRDP. The environment variables won't be set, and your X11 session will work.

Trade-off: With guiApplications=false, you lose WSLg—you can't run individual Linux GUI apps on your Windows desktop anymore. If you need both WSLg for casual app use and XRDP for full desktop sessions, you'll need to toggle this setting and restart WSL when switching between them.

Even with guiApplications=false, WSL's init system may create /tmp/.X11-unix as a symlink pointing to /mnt/wslg/.X11-unix. Since WSLg is disabled, that target doesn't exist—leaving a dangling symlink that breaks XRDP.

How to diagnose:

Check what /tmp/.X11-unix is:

bash
ls -la /tmp/.X11-unix

If it shows a symlink to /mnt/wslg/.X11-unix, that's the problem:

lrwxrwxrwx 1 root root 19 Jan 22 16:09 /tmp/.X11-unix -> /mnt/wslg/.X11-unix

Check the XRDP session manager log:

bash
cat /var/log/xrdp-sesman.log | grep -i "X11-unix"

You'll see errors like:

[ERROR] sesman.c: error creating dir /tmp/.X11-unix

Where the symlink comes from:

  1. WSL's init creates it when booting, even when guiApplications=false (race condition or cached state)
  2. Win-KeX on Kali recreates the symlink when kex stop runs via its wslg-sock restore function

The fix:

bash
sudo rm /tmp/.X11-unix sudo mkdir /tmp/.X11-unix sudo chmod 1777 /tmp/.X11-unix sudo systemctl restart xrdp

Making it permanent (symlink returns on WSL restart):

Add a boot command to /etc/wsl.conf:

ini
[boot] systemd=true command=/bin/bash -c "[ -L /tmp/.X11-unix ] && rm /tmp/.X11-unix && mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix"

This runs before systemd starts services, fixing the symlink before XRDP tries to use it.

Connection Refused

You can't connect at all—Remote Desktop says the connection was refused.

Check XRDP Is Running

bash
sudo service xrdp status

If not running:

bash
sudo service xrdp start

Or with systemd:

bash
sudo systemctl start xrdp

Check the Port

bash
sudo grep "^port=" /etc/xrdp/xrdp.ini

Make sure you're connecting to the right port. If it says port=3390, connect to localhost:3390.

Check for Port Conflicts

bash
sudo ss -tlnp | grep 3390

If nothing is listening, XRDP isn't running properly. Check logs:

bash
sudo journalctl -u xrdp -u xrdp-sesman --no-pager | tail -50

Authentication Failures

You enter your password but it's rejected.

Set a Password

WSL users sometimes don't have passwords set:

bash
sudo passwd $(whoami)

Enter a new password when prompted.

Check PAM Configuration

XRDP uses PAM for authentication. Make sure it's configured:

bash
ls -la /etc/pam.d/xrdp-sesman

If missing, reinstall xrdp:

bash
sudo apt install --reinstall xrdp

GNOME Desktop Not Working

If you installed ubuntu-desktop hoping for a full GNOME experience over XRDP, you'll likely hit several issues.

GNOME Shell Requires 3D Acceleration

GNOME Shell (the default Ubuntu desktop) requires OpenGL hardware acceleration. XRDP's Xorg doesn't provide this. You'll see errors like:

gnome-session-check-accelerated: GL Helper exited with code 512 gnome-session-check-accelerated: GLES Helper exited with code 512

The fix: Use GNOME Flashback instead, which works with software rendering:

bash
sudo apt install gnome-session-flashback -y

Create a proper .xsession that sources your environment before starting the session:

bash
cat > ~/.xsession << 'EOF' #!/bin/sh # Source environment for XDG_CURRENT_DESKTOP if [ -r ~/.xsessionrc ]; then . ~/.xsessionrc fi exec gnome-session --session=gnome-flashback-metacity EOF chmod +x ~/.xsession

Create .xsessionrc with the correct desktop identifier (this is critical for gnome-panel to autostart):

bash
cat > ~/.xsessionrc << 'EOF' export XDG_CURRENT_DESKTOP=GNOME-Flashback:GNOME export XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg EOF

The default /etc/xrdp/startwm.sh should work with this setup—it will execute your .xsession file.

Desktop Portal Services Timeout

Even with GNOME Flashback, you may experience extreme slowness—apps taking minutes to open. Check the journal:

bash
journalctl --user -b | grep -i timeout

If you see messages like:

xdg-desktop-portal.service: start operation timed out xdg-desktop-portal-gnome.service: Failed with result 'timeout' Failed to activate service 'org.freedesktop.impl.portal.desktop.gnome': timed out

These portal services (used for sandboxed app features like file pickers) don't work properly in WSL2 and take 2 minutes to timeout on every operation.

The fix: Mask the problematic services:

bash
# User services systemctl --user mask xdg-desktop-portal.service systemctl --user mask xdg-desktop-portal-gnome.service systemctl --user mask xdg-desktop-portal-gtk.service # System service sudo systemctl mask ModemManager.service

Restart WSL after masking:

powershell
wsl --shutdown

Trade-off: Some GTK file dialogs in sandboxed apps may not work, but the desktop will be responsive.

GNOME Panel Not Appearing

You get a desktop with GNOME Flashback but no panel (taskbar/menu). This happens when XDG_CURRENT_DESKTOP isn't set correctly.

The gnome-panel desktop file contains OnlyShowIn=GNOME-Flashback; so it only autostarts when the desktop environment is correctly identified.

Two things must be true:

  1. Your .xsessionrc must set the correct value:
bash
cat ~/.xsessionrc # Should show: export XDG_CURRENT_DESKTOP=GNOME-Flashback:GNOME
  1. Your .xsession must actually source .xsessionrc:
bash
cat ~/.xsession # Should include: . ~/.xsessionrc (before the exec line)

If either is wrong, recreate both files as shown in the "GNOME Shell Requires 3D Acceleration" section above, then disconnect and reconnect via RDP.

Snap Apps Don't Work (Firefox, etc.)

Ubuntu ships Firefox as a snap package. Snaps have X authentication issues with XRDP sessions:

Authorization required, but no authorization protocol specified Error: cannot open display: :10.0

The fix: Replace snap Firefox with the .deb version from Mozilla's PPA:

bash
# Remove snap version sudo snap remove firefox # Add Mozilla PPA sudo add-apt-repository -y ppa:mozillateam/ppa # Prioritize PPA over snap sudo tee /etc/apt/preferences.d/mozilla-firefox << 'EOF' Package: * Pin: release o=LP-PPA-mozillateam Pin-Priority: 1001 EOF # Install deb version sudo apt update sudo apt install -y --allow-downgrades firefox

This applies to other snap applications too. If an app won't launch over XRDP, check if it's a snap (snap list) and look for a .deb alternative.

Recommendation: Use a Lighter Desktop

GNOME, even in Flashback mode, has many background services that struggle in WSL2. For the smoothest XRDP experience, consider using XFCE or MATE instead—they have fewer dependencies and work reliably without these workarounds.

WSLg Troubleshooting

Issues specific to running individual Linux GUI apps via WSLg.

"Cannot Open Display"

Linux GUI apps fail with display errors.

Check DISPLAY Variable

bash
echo $DISPLAY

Should output :0. If empty or wrong:

bash
export DISPLAY=:0

Restart WSL

The nuclear option that fixes most WSLg issues:

powershell
wsl --shutdown

Then reopen your terminal.

Check WSL Version

WSLg only works with WSL 2:

bash
wsl.exe -l -v

Your distro should show "2" under VERSION. If it shows "1":

powershell
wsl --set-version <distro-name> 2

Remove Old X Server Configuration

If you previously used VcXsrv or X410, old configuration might conflict:

bash
# Check for manual DISPLAY exports grep -r "DISPLAY" ~/.bashrc ~/.profile ~/.zshrc 2>/dev/null

Remove any lines that set DISPLAY to something other than :0.

Black Windows or Rendering Issues

Apps open but display incorrectly.

Update GPU Drivers

WSLg uses GPU acceleration. Driver bugs cause rendering problems.

Check GPU Is Detected

Inside WSL:

bash
glxinfo | grep "OpenGL renderer"

You should see your GPU name. If you see "llvmpipe", that's software rendering—fine for most apps, but 3D-heavy applications will be slower.

Disable GPU Acceleration (Workaround)

If GPU issues persist, you can disable acceleration:

bash
export LIBGL_ALWAYS_SOFTWARE=1 your-app &

Not ideal for performance, but it rules out driver issues.

Audio Not Working

No sound from Linux applications.

Check PulseAudio

bash
pactl info

If it fails or shows errors, restart WSL:

powershell
wsl --shutdown

Check PULSE_SERVER

bash
echo $PULSE_SERVER

Should be /mnt/wslg/PulseServer. If different, you may have old configuration overriding it.

Reference

Log File Locations

When troubleshooting, check these logs:

LogLocationWhat It Contains
XRDP main/var/log/xrdp.logConnection attempts, errors
XRDP session/var/log/xrdp-sesman.logSession creation, authentication
Xorg XRDP~/.xorgxrdp.*.logDisplay server issues
Session errors~/.xsession-errorsDesktop startup failures
systemdjournalctl -u <service>Service-specific logs

View Recent XRDP Activity

bash
# XRDP connection log sudo tail -50 /var/log/xrdp.log # Session manager log sudo tail -50 /var/log/xrdp-sesman.log # Your session errors cat ~/.xsession-errors # Xorg logs (the number varies) cat ~/.xorgxrdp.*.log 2>/dev/null

Common Error Messages

ErrorCauseFix
cannot open display :0DISPLAY not set or WSLg not runningexport DISPLAY=:0 or restart WSL
cannot open display: wayland-0WSLg env vars leaking into XRDPDisable WSLg in .wslconfig
GL Helper exited with code 512GNOME Shell needs 3D accelerationUse gnome-session-flashback instead
xdg-desktop-portal: timed outPortal services failing in WSL2Mask portal services with systemctl
Authorization required, but no authorization protocol specifiedSnap app can't access X displayInstall .deb version instead of snap
Connection refusedXRDP not runningsudo service xrdp start
ACPI: Unable to locate RSDPHardware service in VMsudo systemctl mask acpid
Failed to connect to session busD-Bus not runningsudo service dbus start
Authentication failedNo password or wrong passwordsudo passwd $(whoami)
xrdp-sesman: bind failedPort already in useChange port or kill conflicting process

Quick Diagnostic Script

Run this to gather diagnostic information:

bash
echo "=== WSL Version ===" wsl.exe --version 2>/dev/null || echo "Run from Windows: wsl --version" echo -e "\n=== Init System ===" cat /proc/1/comm echo -e "\n=== DISPLAY ===" echo $DISPLAY echo -e "\n=== XRDP Status ===" sudo service xrdp status 2>/dev/null || systemctl status xrdp 2>/dev/null echo -e "\n=== XRDP Port ===" grep "^port=" /etc/xrdp/xrdp.ini 2>/dev/null echo -e "\n=== Masked Services ===" systemctl list-unit-files --state=masked 2>/dev/null | grep -E "acpi|thermal|upower|bluetooth|modem" echo -e "\n=== .xsession ===" cat ~/.xsession 2>/dev/null || echo "Not found" echo -e "\n=== Recent XRDP Errors ===" sudo tail -10 /var/log/xrdp.log 2>/dev/null

Nuclear Option: Reset Everything

If you've made a mess and want to start fresh:

bash
# Remove desktop and XRDP sudo apt remove --purge xfce4* xrdp ubuntu-desktop* gnome* kde* -y sudo apt autoremove -y # Clean up configs rm -rf ~/.xsession ~/.xsessionrc ~/.Xauthority rm -rf ~/.config/xfce4 ~/.config/gnome* ~/.config/kde* rm -rf ~/.xorgxrdp.*.log ~/.xsession-errors # Reinstall cleanly sudo apt update sudo apt install xfce4 xrdp -y sudo sed -i 's/^port=3389/port=3390/' /etc/xrdp/xrdp.ini echo "startxfce4" > ~/.xsession sudo systemctl enable xrdp --now

Or for a complete reset, delete and recreate the distro:

powershell
# WARNING: Destroys all data in the distro wsl --unregister Ubuntu wsl --install -d Ubuntu

This Series

Further Reading

← Back to all posts