When setting up user-level services on RHEL 7.4 with systemd 219, many developers encounter the frustrating error:
Failed to get D-bus connection: permission denied
This typically occurs after progressing from the initial "connection refused" state, indicating partial but incomplete configuration.
For user-level services to work properly, several components must be correctly configured:
# Essential first step
loginctl enable-linger userservice
Two fundamental unit files must exist in /usr/lib/systemd/user/
:
dbus.service
[Unit]
Description=D-Bus User Message Bus
Requires=dbus.socket
[Service]
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
[Install]
Also=dbus.socket
dbus.socket
[Unit]
Description=D-Bus User Message Bus Socket
[Socket]
ListenStream=%t/bus
ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
[Install]
WantedBy=sockets.target
Also=dbus.service
Your user service should be properly defined in ~/.config/systemd/user/
:
[Unit]
Description=Test user-level service
[Service]
Type=dbus
BusName=com.wtf.service
ExecStart=/home/userservice/userservice.py
Restart=on-failure
[Install]
WantedBy=default.target
Adding this to your .bashrc
is often necessary:
export XDG_RUNTIME_DIR=/run/user/$(id -u)
After setting this, you might encounter a different error:
Failed to get D-Bus connection: no such file or directory
On RHEL systems with SELinux enabled, additional context settings might be required:
# Check current context
ls -Z /run/user/$(id -u)/bus
# If needed, apply proper context
chcon -t user_tmp_t /run/user/$(id -u)/bus
To confirm your configuration is working:
# Verify lingering is enabled
loginctl show-user userservice | grep Linger
# Check dbus socket activation
systemctl --user list-sockets
# Validate environment variables
systemctl --user show-environment | grep DBUS
Follow this diagnostic sequence when encountering issues:
- Verify
XDG_RUNTIME_DIR
is set correctly - Check socket file exists at
/run/user/$(id -u)/bus
- Confirm proper permissions on the socket file
- Ensure SELinux context is appropriate
- Validate DBus service is properly activated
Remember that changes to systemd user units often require a full logout/login cycle rather than just restarting the service.
When working with user-level services in Linux, the systemctl --user
command often throws the frustrating "Failed to get D-bus connection: permission denied" error. This typically occurs when the user's D-Bus instance isn't properly initialized or when permissions aren't correctly set.
Before diving into solutions, verify these fundamental requirements:
# Check if linger is enabled for the user
loginctl show-user userservice | grep Linger
# Verify XDG_RUNTIME_DIR is set
echo $XDG_RUNTIME_DIR
# Should output something like /run/user/1000
Here's a comprehensive solution that addresses all potential causes:
# 1. Enable linger for the user
sudo loginctl enable-linger $(whoami)
# 2. Export essential variables
echo "export XDG_RUNTIME_DIR=/run/user/$(id -u)" >> ~/.bashrc
source ~/.bashrc
# 3. Verify socket creation
ls -la $XDG_RUNTIME_DIR/bus
# 4. Restart the user service manager
systemctl --user daemon-reload
# 5. Check if dbus services are running
systemctl --user list-units --type=service | grep dbus
If you're on RHEL/CentOS with SELinux, check these additional steps:
# Check SELinux context
ls -Z $XDG_RUNTIME_DIR/bus
# Temporarily set SELinux to permissive mode for testing
sudo setenforce 0
# Try your command again
# If it works, you'll need to create proper SELinux policies
sudo setenforce 1
Here's an improved version of your service file with better reliability:
[Unit]
Description=Enhanced User Service Example
After=dbus.socket
Wants=dbus.socket
[Service]
Type=dbus
BusName=com.example.service
ExecStart=/home/%u/service.py
Restart=always
RestartSec=5s
Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus"
[Install]
WantedBy=default.target
After implementing the fixes, verify everything works:
# Check service status
systemctl --user status your-service.service
# Check D-Bus connectivity
dbus-send --session --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames