Skip to main content

Linux command: systemctl

23 July 2026

You install a web server, edit its configuration, and want it running now and again after every reboot. You need to stop a service to update it, check why one crashed, or find out what starts automatically at boot. On almost every modern Linux system, the single command behind all of this is systemctl. It is the control panel for systemd, the program that starts your services, mounts your disks, and brings the whole system up in the right order. Learn systemctl and you learn how a Linux machine really runs.

1. The Basics

The job of systemctl is to query and control systemd, the system and service manager. When your machine boots, the kernel starts one program, and that program is systemd (running as process ID 1). Everything else, from your SSH server to your database to the mounting of disks, is started and supervised by systemd. systemctl is the tool you use to talk to it.

The key idea is the unit. Systemd does not think in terms of "programs" or "scripts". It thinks in units: small description files that say what to run and how. The most common kind is the service unit, but there are units for mount points, timers, sockets, and more. Almost every systemctl command acts on one or more units.

The right mental model: systemd is the manager that runs everything on the machine, and every manageable thing (a service, a mount, a timer) is a unit. systemctl is the remote control you point at those units to start, stop, inspect, and enable them.

This article starts with the plainest use and builds up step by step to the crucial difference between starting and enabling a service, checking state, editing units safely, masking, targets, and the surprising truth that "enabling" a service is really just a symbolic link. By the end, managing services on a systemd machine will feel routine.

1.1 The Simplest Possible Use

Run systemctl with no arguments and it lists every unit systemd currently has in memory, in a pager:

$ systemctl
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  bluetooth.service           loaded active running Bluetooth service
  ssh.service                 loaded active running OpenBSD Secure Shell server
  ...

The output opens in less, so you can scroll and search with /. Press q to quit. The three state columns (LOAD, ACTIVE, SUB) tell you whether systemd read the unit correctly, whether it is running, and the exact sub-state such as running or exited.

1.2 Checking One Service: status

The command you will run most often is status. It shows whether a unit is active, whether it starts at boot, its main process, and the last few log lines from the journal, all in one view:

$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-07-12 09:14:02 CEST; 2h ago
   Main PID: 812 (sshd)
      Tasks: 1 (limit: 18789)
     Memory: 5.2M
        CGroup: /system.slice/ssh.service
             └─812 sshd: /usr/sbin/sshd -D [listener]

Two words on that line matter most. active (running) tells you it is up right now. The word enabled in the Loaded: line tells you it will also start automatically at the next boot. These are two separate facts, and the difference between them is the single most important thing to understand about systemctl, covered in section 5.

1.3 You Usually Need root

Reading state (status, list-units, is-active) works as a normal user. But changing anything, such as starting, stopping, enabling, or disabling a system service, needs administrator rights. Prefix those commands with sudo:

$ systemctl status ssh          # reading: no sudo needed
$ sudo systemctl restart ssh    # changing: sudo required

If you forget sudo, systemd will often pop up a polkit password prompt instead of failing outright, but on a server over SSH it usually just refuses.

Back to top

2. Where the Name Comes From

The name is two parts joined together: system plus ctl.

systemctl  =  SYSTEM + con-TROL

The system part points at systemd, whose own name means "system daemon" (the trailing d is the classic Unix convention for a background daemon, as in sshd or httpd). So systemctl is the tool that controls the system daemon.

The ctl ending is short for control, and it is a house style across the whole systemd family. Once you spot the pattern, a long list of tool names suddenly makes sense:

CommandControls
systemctl services and units
journalctl the journal (logs)
hostnamectl the system hostname
timedatectl time, date, and time zone
loginctl user logins and sessions
systemd-analyze boot time and performance

So systemctl reads as "the control program for the system manager". It is the central member of the family: the others manage one slice of the system, while systemctl manages the units that make up the whole thing.

Back to top

3. A Short History

To understand systemctl you have to know what it replaced, because systemd changed how Linux starts up more than any other single project in the last twenty years.

For most of Unix history, the first program the kernel started was init, and the traditional design was SysV init: a set of shell scripts under /etc/init.d, run in a fixed order by numbered "runlevels". It worked, but it was slow, because it started services one after another, and fragile, because each service was a hand-written script. You controlled a service with commands like service nginx start or by calling the script directly.

systemd, first released in 2010 by Lennart Poettering and Kay Sievers, set out to replace init entirely. Its big ideas were to describe services as small declarative unit files instead of scripts, to start independent services in parallel for a faster boot, and to track every service's processes reliably using kernel control groups (cgroups). Over the following years nearly every major distribution adopted it, and systemctl became the standard way to manage services.

EraMilestone
1980s SysV init and numbered runlevels set the pattern for booting Unix
2006 Ubuntu ships Upstart, an early event-based replacement for init
2010 systemd is released, using declarative units and parallel startup
2014-2015 Debian, Ubuntu, Fedora, RHEL, Arch, and SUSE adopt systemd as default
Today systemd is the standard init on nearly all mainstream Linux distributions

The move was not without argument: systemd is large and does much more than the old init, which some administrators dislike. A few distributions (such as Devuan) deliberately avoid it. But on a default modern install, systemctl is how you manage services, and this article is verified against systemd version 255.

Back to top

4. Simple Use Cases

Four verbs cover almost all day-to-day service work: start, stop, restart, and reload. Each takes one or more unit names. The .service suffix is optional; if you leave off the type, systemd assumes .service.

4.1 Start and Stop a Service

start activates a unit now; stop deactivates it now. Neither affects what happens at the next boot.

$ sudo systemctl start nginx      # bring nginx up now
$ sudo systemctl stop nginx       # shut nginx down now

These commands are quiet on success: no news is good news. Run systemctl status nginx afterwards, or check the exit code, to confirm the change.

4.2 Restart After a Change: restart

When you change a program's configuration file, restart stops the service and starts it again so the new settings take effect:

$ sudo systemctl restart nginx    # full stop, then start

A restart briefly drops the service. For something like a web server that means a short moment where it does not answer, which is where the next command helps.

4.3 Reload Without Dropping the Service: reload

reload asks the running service to re-read its configuration without stopping. It keeps existing connections alive, so a web server or database does not go down:

$ sudo systemctl reload nginx     # re-read config, stay up

The catch: a service can only reload if its author wrote support for it. If it cannot, you get an error. When you are unsure which one you need, reload-or-restart reloads when possible and otherwise restarts:

$ sudo systemctl reload-or-restart nginx
Back to top

5. The Most Important Distinction: start versus enable

This is the one thing everybody gets wrong at first, so it gets its own section. Starting a service and enabling it are two different actions, and doing one does not do the other.

CommandEffectSurvives reboot?
systemctl start X Runs X right now No
systemctl enable X Sets X to start at boot Yes, but does not start it now

If you only start a service, it runs until the next reboot and then never comes back. If you only enable it, it is scheduled for the next boot but is not running yet. Almost always you want both, which is why the --now flag exists:

$ sudo systemctl enable --now nginx    # enable AND start in one step
$ sudo systemctl disable --now nginx   # disable AND stop in one step

5.1 Enable, Disable, and the --now Shortcut

enable creates the link that makes a service start at boot; disable removes it. On their own they do not touch the currently running state:

$ sudo systemctl enable nginx      # will start at boot; not running yet
$ sudo systemctl disable nginx     # will not start at boot; still running now

Remember the rule: start/stop is about now, enable/disable is about boot, and --now bridges the two.

5.2 Asking Yes-or-No Questions: is-active, is-enabled, is-failed

These three commands answer a single question and print one word, which makes them ideal inside scripts. They set the exit code too, so you can test them directly:

$ systemctl is-active nginx        # active  / inactive / failed
$ systemctl is-enabled nginx       # enabled / disabled / static / masked
$ systemctl is-failed nginx        # failed  / active

A word you will meet here is static: it means the unit has no install section to enable, usually because something else pulls it in as a dependency. You cannot enable a static unit, and you do not need to.

5.3 Listing What Exists and What Runs

Two list commands look similar but answer different questions. list-units shows units currently in memory (loaded, mostly active); list-unit-files shows every unit installed on disk and whether each is enabled:

$ systemctl list-units --type=service          # what is loaded now
$ systemctl list-units --type=service --state=running
$ systemctl list-unit-files --type=service     # everything installed, with state
$ systemctl --failed                            # only units that failed

The --failed shortcut (equal to --state=failed) is the fastest health check on a server: an empty list means nothing is broken.

Back to top

6. Advanced Use Cases

6.1 Editing a Unit the Right Way: systemctl edit

Never edit a vendor's unit file under /lib/systemd/system directly; a package update will overwrite it. Instead, use systemctl edit, which creates a small drop-in override file that only changes the settings you name and leaves the original alone:

$ sudo systemctl edit nginx        # opens an override drop-in in an editor

This writes to /etc/systemd/system/nginx.service.d/override.conf. Your lines there win over the vendor's. To replace the whole file instead of layering on top, use systemctl edit --full. After editing, systemd needs to re-read its configuration, which is the next command.

6.2 Reloading systemd Itself: daemon-reload

There are two very different kinds of "reload", and mixing them up is a classic trap:

  • systemctl reload nginx tells the nginx service to re-read its own config.
  • systemctl daemon-reload tells systemd itself to re-read all unit files.

Whenever you add, edit, or remove a unit file, run daemon-reload so systemd notices the change, then restart the affected service:

$ sudo systemctl daemon-reload     # systemd re-reads unit files
$ sudo systemctl restart nginx     # apply the new unit definition

If you edit a unit and your changes seem ignored, a missing daemon-reload is the usual reason.

6.3 Writing Your Own Service Unit

Sooner or later you want to run your own program as a managed service, so it starts at boot, restarts on failure, and logs to the journal like any other unit. You do this by writing a small unit file under /etc/systemd/system/. A service unit has three sections:

$ sudo nano /etc/systemd/system/myapp.service

[Unit]
Description=My Application
After=network.target

[Service]
ExecStart=/opt/myapp/app.sh
Restart=on-failure
User=myapp

[Install]
WantedBy=multi-user.target

Each section has a clear job:

SectionAnswers
[Unit] What is it, and when should it start relative to others
[Service] What to run (ExecStart), as whom, and how to restart it
[Install] Which target pulls it in when you enable it

After creating the file, tell systemd about it and turn it on:

$ sudo systemctl daemon-reload      # systemd notices the new file
$ sudo systemctl enable --now myapp  # start it now and at every boot

The Restart=on-failure line is one of the reasons to prefer a real unit over a hand-run script: systemd will bring your program back up if it crashes.

6.4 Controlling Order and Requirements

The [Unit] section is where you say how a unit relates to others, and two different ideas are easy to confuse: ordering (when) and requirement (whether):

DirectiveMeaning
After= Ordering only: start this unit after the named one
Before= Ordering only: start this unit before the named one
Requires= Hard requirement: if the named unit fails or stops, this one stops too
Wants= Soft requirement: pull the named unit in, but do not fail if it does not start

The trap is that ordering and requirement are separate. Requires= says the other unit must be there, but it does not say to wait for it; you almost always pair it with After= to also get the order right:

[Unit]
Requires=postgresql.service
After=postgresql.service

Wants= is the gentler and more common choice: it is what enable writes for you behind the scenes, and it keeps one failing dependency from dragging your service down with it.

6.5 Understanding Dependencies: list-dependencies

Once units depend on each other, you often need to see the whole tree. list-dependencies shows what a unit pulls in, and with --reverse, what depends on it:

$ systemctl list-dependencies nginx    # what nginx pulls in
$ systemctl list-dependencies --reverse nginx   # what depends on nginx

This is how you answer "why does this service start?" and "what breaks if I stop that one?".

6.6 Hardening a Service: Sandboxing

One of systemd's most underused powers is that the [Service] section can lock a service into a sandbox, shrinking what a compromised program can reach. You add these as plain directives, no container needed:

DirectiveEffect
ProtectSystem=strict Mount the whole filesystem read-only for the service
ProtectHome=true Hide /home and /root from the service
PrivateTmp=true Give the service its own private /tmp
NoNewPrivileges=true Stop the service ever gaining more privileges (no setuid)
PrivateDevices=true Hide real hardware device nodes

You can measure how well a service is locked down with a built-in scanner that scores each unit and suggests what to add:

$ systemd-analyze security nginx    # exposure score and per-setting advice

For a service exposed to the internet, a few of these lines can turn a full-system compromise into a contained one. Add them through systemctl edit so they survive updates.

6.7 Seeing the Real Unit File: cat and show

systemctl cat prints the exact unit file systemd loaded, including any drop-ins layered on top, so you see the effective definition:

$ systemctl cat nginx              # the unit file plus any overrides

systemctl show goes further and dumps every resolved property as KEY=VALUE, which is how you check what a setting actually became:

$ systemctl show nginx -p MemoryCurrent -p ExecStart

6.8 Masking: The Strongest "Off" Switch

disable stops a service starting at boot, but something else can still pull it in as a dependency, or you can still start it by hand. mask is the absolute block: it makes the unit impossible to start at all, by anyone, until you unmask it:

$ sudo systemctl mask nginx        # nginx cannot be started at all now
$ sudo systemctl unmask nginx      # allow it again

Use masking when you truly want a service dead, for example replacing a distribution's default web server with your own. Under the hood, masking links the unit to /dev/null, which section 7 explains.

6.9 Targets: Grouping Units into System States

A target is a special unit that groups other units, used to describe a whole system state. Targets are systemd's replacement for the old runlevels:

TargetRough old runlevelMeaning
multi-user.target 3 Full system, networking, no graphical login
graphical.target 5 Everything in multi-user, plus a desktop
rescue.target 1 Single-user rescue shell, minimal services
emergency.target - Barest shell, almost nothing started

You can see the boot default, change it, or switch the running system into another target:

$ systemctl get-default                       # e.g. graphical.target
$ sudo systemctl set-default multi-user.target  # boot without a desktop next time
$ sudo systemctl isolate rescue.target          # switch to rescue mode now

6.10 Reboot, Power Off, and Suspend

Because systemd manages the whole system state, it also owns shutdown and sleep. These verbs replace the older separate commands:

$ systemctl reboot         # restart the machine
$ systemctl poweroff       # shut down and power off
$ systemctl suspend        # sleep to RAM
$ systemctl hibernate      # sleep to disk
Back to top

7. Something Most Users Do Not Know

The word enable sounds like it flips a switch deep inside systemd. It does something much simpler: it creates a symbolic link. A unit file has an [Install] section that says which target wants it, for example WantedBy=multi-user.target. When you enable the unit, systemd creates a symlink to it inside that target's .wants directory:

$ sudo systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service
               → /lib/systemd/system/nginx.service.

At boot, systemd starts multi-user.target, sees the symlinks in its .wants directory, and starts each linked unit. That is the entire mechanism. disable simply deletes the link. Once you know this, the whole enable/disable system stops being magic and becomes files you can list with ls.

Enabling is not a hidden database flag. It is a symlink in a target's .wants directory. Boot is systemd following those links. Everything you can enable, you could create by hand with ln -s (though you should not; let systemctl do it).

Masking uses the same trick in reverse. When you mask a unit, systemd links its name to /dev/null:

$ sudo systemctl mask nginx
Created symlink /etc/systemd/system/nginx.service → /dev/null.

Because the unit now "is" the empty device, systemd sees nothing to run and refuses every attempt to start it, whether by you, at boot, or as a dependency. This is why masking is stronger than disabling: a disabled unit still exists and can be started; a masked one points at nothing.

7.3 systemctl Does Not Touch Services Directly: It Speaks D-Bus

When you run systemctl restart nginx, the systemctl program does not start or stop anything itself. It sends a message to systemd (the process with PID 1) over D-Bus, the standard message bus Linux uses for programs to talk to each other. Systemd receives the request, checks whether you are allowed to make it, does the actual work, updates the unit's state, and writes the result to the journal.

This design explains several things you may have noticed:

  • A polkit password dialog can pop up on a desktop, because D-Bus lets systemd ask an authorization service whether to permit the action.
  • You can manage a machine remotely at the protocol level with systemctl -H user@host, because the request is just a message that can travel.
  • systemctl is really a thin client: the intelligence lives in the systemd manager it talks to, not in the command.

7.4 The Same Unit Can Live in Three Places

Systemd looks for unit files in several directories, and when the same unit name appears in more than one, a fixed order of precedence decides which wins. From highest priority to lowest:

DirectoryPurposePriority
/etc/systemd/system/ Your local changes and custom units Highest (admin wins)
/run/systemd/system/ Runtime units, gone after reboot Middle
/usr/lib/systemd/system/ Vendor and package units Lowest

This ranking is the whole reason drop-ins and systemctl edit work: your file in /etc always beats the package's file in /usr/lib, so an update to the package cannot silently undo your change. On Debian and Ubuntu, /lib/systemd/system is the same location as /usr/lib/systemd/system. To see which file actually won, use systemctl cat.

7.5 You Have Your Own Personal systemd

Systemd runs a second, separate instance just for your login: the user manager. It manages services that belong to you and do not need root, such as a desktop component or a personal backup timer. You control it by adding --user to any command:

$ systemctl --user status               # your own units
$ systemctl --user start myapp          # a service you own, no sudo
$ systemctl --user enable --now myapp

User units live under ~/.config/systemd/user/. This explains a common confusion: a service you started with systemctl --user will not show up under a plain systemctl status, because that queries the system manager, not yours. If you want a user service to keep running after you log out, enable lingering for your account with loginctl enable-linger.

7.6 Every Manageable Thing Is a Unit, Not Just Services

Because people use systemctl mostly for services, it is easy to forget that systemd manages many other unit types the same way. The suffix tells you the type:

SuffixUnit typeManages
.service Service A daemon or program
.socket Socket A port or socket that starts a service on first use
.timer Timer A scheduled job, a modern replacement for cron
.mount Mount A filesystem mount point
.target Target A group of units and a system state

So systemctl list-timers shows your scheduled jobs, and systemctl start something.mount mounts a filesystem. The same start, stop, enable, and status verbs work on all of them.

7.7 Where systemctl Stops, Other Tools Take Over

systemctl controls units; a few neighbours pick up where it ends:

  • journalctl -u nginx reads a unit's logs; systemctl status only shows the last few lines.
  • systemd-analyze blame shows which units slowed your boot the most, and systemd-analyze critical-chain shows the ordered chain that gated it.
  • systemctl list-timers lists scheduled timers; edit them as .timer units.
  • loginctl manages user sessions and lingering; hostnamectl and timedatectl handle the hostname and clock.

Knowing this boundary keeps you efficient: systemctl to control a service, journalctl to read why it failed.

Back to top

8. Best Practices

  • Decide "now" and "at boot" on purpose. For a service you want permanently, use enable --now. For a one-off, use plain start. Being clear about which you mean prevents surprises after a reboot.
  • Prefer reload over restart when it exists. A reload keeps connections alive; a restart drops them for a moment. Fall back to reload-or-restart when unsure.
  • Never edit vendor unit files directly. Use systemctl edit to add a drop-in override, so a package update cannot wipe your changes.
  • Run daemon-reload after any unit-file change. Otherwise systemd keeps using the old definition and your edits appear to do nothing.
  • Give your own program a real unit. A short [Unit]/[Service]/[Install] file with Restart=on-failure beats a hand-run script: it starts at boot, restarts on crash, and logs to the journal.
  • Sandbox internet-facing services. Add a few lines such as ProtectSystem=strict, PrivateTmp=true, and NoNewPrivileges=true, and check the result with systemd-analyze security.
  • Check systemctl --failed regularly. On a server it is the fastest way to spot a service that quietly died.
  • Use systemctl cat to see the truth. It shows the real, effective unit including overrides, which avoids guessing about which file is in force.
  • Read the manual when unsure. The behaviour is fully documented; man systemctl and man systemd.unit are the reference.
$ man systemctl         # the command and all its verbs
$ man systemd.service    # how to write a service unit
$ systemctl --help       # a quick summary of the commands
Back to top

9. Common Mistakes

9.1 Myth versus Reality

MythReality
"systemctl start makes a service permanent." It runs the service now only. Use enable (or enable --now) to make it start at boot.
"enable also starts the service." By itself it only schedules it for the next boot. Add --now to start it as well.
"reload and daemon-reload are the same." reload re-reads the service's own config; daemon-reload re-reads systemd's unit files. They solve different problems.
"disable guarantees a service can never run." A disabled unit can still be started by hand or pulled in as a dependency. Use mask for an absolute block.
"Editing the file in /lib/systemd/system is fine." A package update overwrites it. Use systemctl edit to keep changes in a safe drop-in.

9.2 Other Traps to Avoid

  • Forgetting daemon-reload after editing a unit. Systemd caches unit files in memory. Until you reload, it uses the old version and your edit seems ignored.
  • Restarting when a reload would do. On a busy web or database server, a needless restart drops live connections. Check whether reload is supported first.
  • Looking for a user service in the system view. A unit started with --user will not appear under a plain systemctl status. Add --user to see it.
  • Reading logs with the wrong tool. systemctl status shows only the last lines. For the full history of a unit, switch to journalctl -u name.
  • Confusing the service name with the program name. The unit may be ssh.service while the process is sshd. Use systemctl list-units or tab completion to find the exact unit name.
Back to top

10. Summary

The systemctl command is the control panel for systemd, and systemd runs everything on a modern Linux machine. Learn a handful of verbs and one key distinction, and managing services becomes calm and predictable instead of guesswork.

  • systemctl queries and controls systemd, the manager that starts every service, mount, and timer as a unit.
  • The name means "system control", part of the systemd family alongside journalctl and timedatectl.
  • It replaced SysV init scripts with declarative unit files and parallel startup, arriving with systemd in 2010.
  • Manage a running service with start, stop, restart, and reload; check it with status.
  • The crucial distinction: start/stop act now, enable/disable act at boot, and --now does both.
  • Ask yes-or-no with is-active, is-enabled, and is-failed; list state with list-units, list-unit-files, and --failed.
  • Write your own service as a small [Unit]/[Service]/[Install] file, order it with After=/Before=, and require others with Wants=/Requires=.
  • Harden a service in its [Service] section with sandboxing (ProtectSystem=, PrivateTmp=, NoNewPrivileges=), scored by systemd-analyze security.
  • Edit units safely with systemctl edit (a drop-in), then run daemon-reload so systemd notices.
  • Block a service completely with mask; group units and system states with targets like multi-user.target.
  • Under the hood, enabling is a symlink in a target's .wants directory, masking is a symlink to /dev/null, and systemctl reaches systemd over D-Bus.
  • A unit in /etc/systemd/system always overrides the vendor copy in /usr/lib/systemd/system, which is what makes drop-ins survive updates.
  • You have a second, personal systemd reached with --user, and every manageable thing (service, timer, mount, target) is a unit.

This is the quick reference worth keeping:

systemctl status nginx           is it running, enabled, and healthy
systemctl start nginx            run it now
systemctl stop nginx             shut it down now
systemctl restart nginx          full stop then start
systemctl reload nginx           re-read config, stay up
systemctl enable nginx           start at boot (not now)
systemctl enable --now nginx     start at boot AND now
systemctl disable --now nginx    stop now AND at boot
systemctl is-active nginx        one-word running check
systemctl is-enabled nginx       one-word boot check
systemctl --failed               list everything that failed
systemctl list-units --type=service   loaded services
systemctl list-unit-files        every installed unit and its state
systemctl edit nginx             safe drop-in override
systemctl daemon-reload          reload unit files after editing
systemctl cat nginx              show the effective unit file
systemctl mask nginx             block a service completely
systemctl list-dependencies nginx     what it needs
systemd-analyze security nginx   score a service's sandboxing
systemctl --user status          your own user services
systemctl reboot                 restart the machine

Managing services well is one of the quiet skills that separates a calm server administrator from a stressed one: the difference between a site that comes back cleanly after every reboot and one that silently forgets to start a service at the worst possible moment. If your servers have services that do not survive a restart, changes that never seem to take effect, or a boot that no one fully understands, it pays to have systemd set up correctly before the next incident, so the machine behaves exactly as you expect.

Back to top
Linux command: systemctl
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.