Manage systemd Targets in Linux

Tested on RHEL 10.2 (Coughlan)
Package systemd 257-23.el10_2.2
Applies to Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux
Privilege sudo or root for set-default, isolate, rescue, and emergency
Scope Target concepts, get-default and set-default, isolate, list-dependencies, rescue and emergency targets, temporary boot overrides with systemd.unit=, and runlevel mapping. Does not cover full unit file authoring, su or sudo switching, service start/stop tutorials, or full GRUB configuration.
Related guides systemctl command
Boot and shutdown
grubby command
Linux command line
RHCSA tutorial
IMPORTANT
This guide covers systemd targets—default boot state, live target switches, and rescue or emergency entry. It does not teach general service management, user switching with su or sudo, or editing GRUB entries beyond a one-line systemd.unit= override at boot.

A systemd target is not a mysterious runlevel number. It is a unit that groups other units and marks a synchronization point during boot: systemd starts dependencies, waits where targets say to wait, and leaves you in a defined system state such as multi-user text mode or a full graphical desktop.


What Is a systemd Target?

systemd manages work through units. A unit file describes something systemd can start, stop, or track—a service, a mount, a socket, or a target.

A target unit ends with .target. It usually does not run a long-lived process of its own. Instead it:

  • Groups related services, mounts, and other units that belong together at a boot stage
  • Acts as a synchronization point so systemd can order startup and signal “this milestone is reached”
  • Pulls units into the transaction through dependencies such as Requires= and Wants=, while After= and Before= control startup and shutdown ordering

Think of multi-user.target as “the cluster of units that make a usable multi-user server” rather than a single daemon you restart.

On this lab host, both multi-user.target and graphical.target are active while the desktop is running—graphical target units sit on top of multi-user dependencies.

bash
systemctl is-active multi-user.target graphical.target rescue.target emergency.target

Sample output:

output
active
active
inactive
inactive

rescue.target and emergency.target stay inactive during normal operation.


systemd Target Quick Reference

Task Command
Current default for next boot systemctl get-default
Set default systemctl set-default multi-user.target
Switch target now systemctl isolate multi-user.target
Rescue mode systemctl rescue
Emergency mode systemctl emergency
List active target units systemctl list-units --type=target
Show dependencies systemctl list-dependencies multi-user.target

isolate, rescue, and emergency change the running system. set-default affects future boots until you change it again.


Common systemd Targets

Administrators interact with a small subset of the 79 target unit files shipped on RHEL 10. The rest are internal milestones (local-fs.target, network-online.target, and similar).

Target Role
basic.target Early “basic system” milestone after local filesystems and core initialization
multi-user.target Multi-user system with command-line services—SSH, cron, logging, and typical server daemons
graphical.target Multi-user plus graphical login (gdm and desktop stack)
rescue.target Maintenance shell with local filesystems and sysinit dependencies
emergency.target Minimal emergency shell with very few dependencies
poweroff.target Shutdown and power-off transaction

reboot.target and poweroff.target complete shutdown transactions—see boot and shutdown for systemctl reboot, poweroff, and scheduled shutdown workflows.

graphical.target depends on multi-user.target in the dependency tree, not beside it as a peer runlevel.


Check the Default Boot Target

The default target is the target systemd tries to reach on boot. It is stored as a symlink at /etc/systemd/system/default.target.

bash
systemctl get-default

Sample output:

output
graphical.target

Read the symlink directly when you want the path systemd will follow:

bash
readlink -f /etc/systemd/system/default.target

Sample output:

output
/usr/lib/systemd/system/graphical.target
bash
ls -l /etc/systemd/system/default.target

Sample output:

output
lrwxrwxrwx. 1 root root 40 Aug  3 11:45 /etc/systemd/system/default.target -> /usr/lib/systemd/system/graphical.target

get-default reports the name; readlink shows which file the symlink points at under /usr/lib/systemd/system/.


Change the Default Boot Target

Use set-default when a server should boot to text multi-user mode without a display manager, or when a workstation should return to graphical after maintenance.

Switch the next-boot default to multi-user:

bash
sudo systemctl set-default multi-user.target

Sample output:

output
Removed '/etc/systemd/system/default.target'.
Created symlink '/etc/systemd/system/default.target' → '/usr/lib/systemd/system/multi-user.target'.

Confirm the change:

bash
systemctl get-default

Sample output:

output
multi-user.target

The running desktop does not disappear immediately. graphical.target can remain active until you reboot or isolate:

bash
systemctl is-active graphical.target

Sample output on this host right after set-default:

output
active

Restore graphical as the default when the lab or server should boot to a GUI again:

bash
sudo systemctl set-default graphical.target

Sample output:

output
Removed '/etc/systemd/system/default.target'.
Created symlink '/etc/systemd/system/default.target' → '/usr/lib/systemd/system/graphical.target'.

Reboot and run get-default plus systemctl is-active graphical.target when you need to prove the full boot path—not only the symlink.


Switch to Another Target Immediately

systemctl isolate starts the named target and its dependencies, then stops units that are not required by that target unless they have IgnoreOnIsolate=yes.

That is how you move a live system from graphical to multi-user without editing the default symlink:

bash
sudo systemctl isolate multi-user.target

Before isolating a target over SSH, verify that networking and sshd are dependencies of the destination target. multi-user.target normally keeps them on RHEL, but custom configurations can differ. Prefer scheduling maintenance, testing on a console, or using set-default plus reboot when a hard cutover is acceptable.

List what is active on a normal graphical boot—you should see both graphical.target and multi-user.target.

bash
systemctl list-units --type=target --state=active --no-pager

Sample output (trimmed):

output
UNIT                     LOAD   ACTIVE SUB    DESCRIPTION
  basic.target             loaded active active Basic System
  cryptsetup.target        loaded active active Local Encrypted Volumes
  getty.target             loaded active active Login Prompts
  graphical.target         loaded active active Graphical Interface
  integritysetup.target    loaded active active Local Integrity Protected Volumes
  local-fs-pre.target      loaded active active Preparation for Local File Systems
  local-fs.target          loaded active active Local File Systems
  multi-user.target        loaded active active Multi-User System
  network-online.target    loaded active active Network is Online
  network-pre.target       loaded active active Preparation for Network
  network.target           loaded active active Network

Return to graphical on a desktop with:

bash
sudo systemctl isolate graphical.target

For day-to-day unit control outside target changes, see the systemctl command reference.


Understand Target Dependencies

Targets start other units. list-dependencies walks Requires=, Requisite=, Wants=, and related edges—useful when you ask “what does multi-user actually pull in?”

bash
systemctl list-dependencies multi-user.target --no-pager | head -25

Sample output:

output
multi-user.target
● ├─atd.service
○ ├─audit-rules.service
● ├─auditd.service
● ├─avahi-daemon.service
● ├─chronyd.service
● ├─crond.service
● ├─cups.path
● ├─cups.service
● ├─firewalld.service
○ ├─insights-client-boot.service
● ├─irqbalance.service
○ ├─kdump.service
● ├─libstoragemgmt.service
● ├─mcelog.service
○ ├─mdmonitor.service
● ├─ModemManager.service
● ├─NetworkManager.service
● ├─plymouth-quit-wait.service
○ ├─plymouth-quit.service
● ├─rhsmcertd.service
● ├─rsyslog.service
○ ├─smartd.service
● ├─sshd.service
○ ├─sssd.service

marks active units; marks inactive ones still listed in the dependency tree.

Graphical target adds desktop units on top of multi-user:

bash
systemctl list-dependencies graphical.target --no-pager | head -20

Sample output:

output
graphical.target
● ├─accounts-daemon.service
● ├─gdm.service
○ ├─nvmefc-boot-connections.service
● ├─rtkit-daemon.service
● ├─switcheroo-control.service
○ ├─systemd-update-utmp-runlevel.service
● ├─tuned-ppd.service
● ├─udisks2.service
● ├─upower.service
● └─multi-user.target
●   ├─atd.service
○   ├─audit-rules.service
●   ├─auditd.service
...

Property lines show the difference between hard requirements and soft wants:

bash
systemctl show multi-user.target -p Requires -p Wants -p Conflicts --no-pager

Sample output:

output
Requires=basic.target
Wants=avahi-daemon.service plymouth-quit.service systemd-update-utmp-runlevel.service mcelog.service NetworkManager.service tuned.service mdmonitor.service rhsmcertd.service audit-rules.service remote-cryptsetup.target ModemManager.service systemd-ask-password-wall.path vmtoolsd.service libstoragemgmt.service cups.service crond.service irqbalance.service systemd-logind.service insights-client-boot.service sshd.service sssd.service cups.path chronyd.service smartd.service remote-fs.target plymouth-quit-wait.service auditd.service rsyslog.service firewalld.service systemd-user-sessions.service getty.target atd.service kdump.service
Conflicts=rescue.service shutdown.target rescue.target

Requires= failures are binding; Wants= failures are tolerated. This article stops at target-level dependency reading—not a full unit-design tutorial.


Rescue Mode

Rescue mode is for repair when the system boots but you need a root maintenance environment with local filesystems available. RHEL documents rescue as mounting local file systems and starting required services before a rescue shell.

Enter rescue on a running system:

bash
sudo systemctl rescue

systemctl rescue switches to rescue.target, similar to systemctl isolate rescue.target, but also sends a wall message to logged-in users. Use systemctl --no-wall rescue when you intentionally want to suppress that notification. systemd may still prompt for the root password before switching.

Inspect what rescue pulls in:

bash
systemctl list-dependencies rescue.target --no-pager | head -15

Sample output:

output
rescue.target
○ ├─rescue.service
○ ├─systemd-update-utmp-runlevel.service
● └─sysinit.target
●   ├─dev-hugepages.mount
●   ├─dev-mqueue.mount
●   ├─dracut-shutdown.service
...

Return to normal operation after repair:

bash
sudo systemctl isolate multi-user.target

Use graphical.target instead when the host normally runs a desktop.


Emergency Mode

Emergency mode is smaller than rescue. The emergency target requires emergency.service and little else:

bash
systemctl list-dependencies emergency.target --no-pager

Sample output:

output
emergency.target
○ └─emergency.service

Networking, most mounts beyond root, and application services are not part of this tree. On RHEL 10, emergency mode mounts only the root filesystem, read-only, with no other local filesystems or network. Emergency helps when boot never reaches multi-user and you need a root shell on the console to fix unit files or fstab entries.

bash
sudo systemctl emergency

Equivalent to systemctl isolate emergency.target. Expect a root password prompt and minimal tooling.

If you need to edit /etc/fstab or another file under /, remount root read-write first:

bash
mount -o remount,rw /

After changing /etc/fstab, run systemctl daemon-reload before you attempt to continue boot or isolate back to multi-user.


Rescue vs Emergency Mode

Aspect Rescue (rescue.target) Emergency (emergency.target)
Purpose Filesystem repair, config fixes with mounts Bare-minimum shell when boot is badly broken
Typical filesystems Local filesystems from sysinit path Root only, normally read-only
Networking Not the focus; more units than emergency Generally unavailable
Entry command systemctl rescue systemctl emergency
Dependency depth sysinit.target plus rescue.service emergency.service only
Return path systemctl isolate multi-user.target or graphical.target Same after root cause is fixed

Start with rescue when the system still boots and you need mounted volumes. Drop to emergency when even rescue dependencies fail.


Select a Target Temporarily from the Bootloader

You can boot into a different target once without set-default. At the bootloader, edit the kernel command line for the selected entry and append:

text
systemd.unit=rescue.target

or:

text
systemd.unit=emergency.target

Other common one-boot overrides include systemd.unit=multi-user.target when graphical startup fails.

The parameter applies only to that boot. After you remove it or pick the default menu entry again, the system follows default.target from /etc/systemd/system/.

Full GRUB menu editing, password protection, and persistent kernel arguments belong in bootloader guides such as grubby command—this section only names the systemd.unit= knob.


systemd Targets vs SysV Runlevels

Legacy documentation still mentions runlevels. systemd targets overlap the idea but are not numeric runlevels internally.

Legacy runlevel Typical systemd target Notes
0 poweroff.target Shutdown
1, s rescue.target Single-user maintenance
2 multi-user.target Legacy compatibility mapping
3 multi-user.target Traditional text multi-user runlevel
4 multi-user.target Legacy compatibility mapping; no distinct systemd state
5 graphical.target Graphical login
6 reboot.target Reboot

Traditional SysV installations sometimes reserved runlevel 4 for site-specific services. systemd does not define a separate target for that legacy convention—systemd.unit=multi-user.target is the compatibility mapping for runlevels 2, 3, and 4.

On this RHEL 10 host, runlevel still prints the SysV compatibility view:

bash
runlevel

Sample output:

output
N 5

N means no previous runlevel recorded for this boot; 5 matches graphical mode. Prefer systemctl get-default and target names in automation—the mapping is approximate, not a guarantee that every unit matches old runlevel scripts.


Custom Targets

Sites sometimes define custom targets to group application stacks. That requires writing unit files with AllowIsolate=yes, dependency lines, and ordering—a topic for a dedicated systemd unit authoring guide.

For RHCSA-style administration, knowing how to read list-dependencies and switch existing targets is enough. Skip custom target design until you routinely maintain your own unit files.


Troubleshoot Target Problems

Symptom Likely cause Fix
Target not found / isolate fails Misspelled or nonexistent target Check systemctl list-unit-files --type=target; .target may be omitted with isolate
isolate fails or hangs Target conflicts or broken required unit journalctl -xb; fix failing Requires= unit; try rescue
Boots to multi-user but default is graphical set-default not applied or symlink overridden readlink -f /etc/systemd/system/default.target; re-run set-default
Graphical target active but no GUI Display manager failed systemctl status gdm; fix graphics stack—not the target symlink alone
get-default disagrees with symlink Stale admin edit Replace symlink with set-default instead of manual ln -sf
Rescue or emergency asks for root password Expected security behavior Authenticate as root on console or fix root credentials
Network lost after isolate to rescue Rescue does not target network-online Start NetworkManager or sshd manually if needed for remote repair
SSH drops after target isolation sshd or networking was not required by the destination target Check target dependencies before remote isolation; use console or out-of-band access for rescue/emergency transitions

Practical Target Examples

These steps mirror server maintenance: read the default, change it for headless boot, confirm the symlink, and inspect dependencies. The commands below stay on a running host; the reboot outcome is described separately so the sequence stays logical.

Check what the next boot will use:

bash
systemctl get-default

Sample output:

output
graphical.target

Point future boots at multi-user for a headless server profile:

bash
sudo systemctl set-default multi-user.target

Verify the symlink—not only get-default:

bash
ls -l /etc/systemd/system/default.target

Sample output:

output
lrwxrwxrwx. 1 root root 41 Aug  8 14:46 /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target

Remember the live GUI may still run until reboot:

bash
systemctl is-active graphical.target

Sample output immediately after set-default multi-user:

output
active

Inspect what multi-user will start on the next boot:

bash
systemctl list-dependencies multi-user.target --no-pager | head -15

If you reboot before restoring graphical.target as the default, the system should start in multi-user mode with graphical.target inactive and runlevel typically reporting N 3. To switch the current session to graphical, run systemctl isolate graphical.target; to make graphical mode persistent again, run systemctl set-default graphical.target.

On a desktop lab host, restore graphical as the default when you finish so the next boot returns to a GUI:

bash
sudo systemctl set-default graphical.target
bash
systemctl get-default

Sample output:

output
graphical.target

References


Summary

systemd targets describe where boot should end up and which units belong to that milestone. multi-user.target groups the services that make a text-mode server usable; graphical.target layers a display manager and desktop stack on that tree. Targets synchronize boot—they are not simply renamed runlevel numbers.

Daily administration splits along two axes. systemctl get-default and set-default control the default.target symlink for future boots without necessarily changing what is running now. systemctl isolate, rescue, and emergency change the live system and can stop graphical or network units you still depend on—plan console or out-of-band access before isolating away from a desktop over SSH.

Rescue and emergency are repair entry points, not everyday modes. Rescue brings in sysinit and local filesystems; emergency is the smallest shell systemd offers. One-boot systemd.unit=rescue.target on the kernel line fixes a single failed boot without touching set-default. When dependencies confuse you, list-dependencies and systemctl show on the target explain which services multi-user or graphical actually wants.

For power-off and reboot transactions (poweroff.target, reboot.target), use the boot and shutdown guide. For unit start, stop, and enable outside target changes, keep the systemctl command reference nearby.


Frequently Asked Questions

1. What is the difference between systemctl set-default and systemctl isolate?

set-default updates the default.target symlink for future boots only. The running system stays on the current target until you reboot or run isolate. isolate switches the live system to another target now by starting its dependency tree and stopping units that are not required by that target.

2. Does runlevel 3 equal multi-user.target on RHEL?

systemd maps runlevels 2, 3, and 4 to multi-user.target for compatibility, and runlevel 5 to graphical.target. Traditional SysV installs sometimes reserved runlevel 4 for site-specific use, but that is separate from systemd current mapping. Use target names in scripts and automation.

3. When should I use rescue mode instead of emergency mode?

Rescue mounts local filesystems and starts sysinit dependencies before a root maintenance shell. Emergency is smaller: emergency.service on the console with minimal dependencies. Start with rescue when you need mounted volumes and more tooling; use emergency when boot is badly broken.

4. Why is graphical.target still active after set-default multi-user.target?

set-default only changes the symlink under /etc/systemd/system/default.target. Active units on a running host change when you isolate, reboot, or when systemd naturally transitions during boot—not when you update the default for next boot.

5. Can I boot into rescue without changing the default target?

Yes. Append systemd.unit=rescue.target to the kernel command line for that boot only, or run systemctl isolate rescue.target on a running system. The default.target symlink stays unchanged unless you also run set-default.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)