systemctl is the primary command-line interface to systemd, the init system and service manager used by most modern Linux distributions. In system initialization, it is the tool administrators use to start, stop, restart, enable, disable and inspect units such as services, sockets, timers, mounts and targets, and to change the overall system state, for example to reboot or switch to a rescue target.
systemctl does not run services itself. It sends requests over D-Bus to the systemd manager, process ID 1 for the system instance or a per-user manager with the --user option, and systemd carries out the job, tracks dependencies and records the result.
How systemctl communicates with systemd
Each systemctl command translates into a job that systemd queues and executes. A request such as systemctl start nginx.service asks the manager to bring the unit to the active state; systemd then resolves its dependencies, orders them according to After= and Before= directives, starts the required units first and reports success or failure.
The tool talks to the local manager by default, but it can address a remote host over SSH with -H user@host or a container with -M name. Read-only queries such as status work for ordinary users, while state-changing operations require root privileges or a polkit authorization.
| State | Meaning | Commands | Persists across reboot |
|---|---|---|---|
| Runtime state | Whether a unit is running now | start, stop, restart, reload | No |
| Enablement state | Whether a unit starts at boot or on trigger | enable, disable | Yes |
| Masked state | Unit cannot be started at all | mask, unmask | Yes |
Separating these two dimensions is the most important concept for new administrators: enabling a service does not start it, and stopping a service does not disable it. The shortcut systemctl enable --now does both at once.
Essential systemctl commands
Most daily administration uses a small set of subcommands. The table groups them by purpose; unit names can omit the .service suffix, which systemctl adds automatically.
| Subcommand | Purpose | Typical use |
|---|---|---|
| status | Shows state, main PID, cgroup and recent log lines | First step in troubleshooting |
| start / stop / restart | Changes runtime state | Applying a new binary or recovering |
| reload | Asks the service to reread configuration | Web servers without dropping connections |
| enable / disable | Creates or removes install symlinks | Controlling start at boot |
| mask / unmask | Links the unit to /dev/null | Preventing any start, even as a dependency |
| daemon-reload | Rereads all unit files | After editing or adding unit files |
| list-units / list-unit-files | Lists loaded units or installed unit files | Inventory and auditing |
| is-active / is-enabled / is-failed | Returns state as an exit code | Scripts and health checks |
The edit subcommand creates a drop-in override under /etc/systemd/system/<unit>.d/, which changes selected directives without modifying the vendor unit in /usr/lib/systemd/system/. systemctl cat shows the effective unit including all drop-ins, and systemctl show prints every resolved property in machine-readable form.
Unit states and how to read status output
The status output combines the load state, the active state and a more detailed sub-state, followed by the last lines from the journal. Reading these fields correctly answers most questions about why a service is not running.
| Field and value | Meaning | Typical next step |
|---|---|---|
| loaded | Unit file parsed successfully | None |
| not-found | No unit file with that name | Check spelling or package installation |
| masked | Unit deliberately blocked | Unmask if the block is unintended |
| active (running) | Main process is alive | None |
| active (exited) | One-shot unit completed successfully | Expected for setup tasks |
| failed | Process exited with an error or timed out | Read the journal, fix, reset-failed |
| activating | Start in progress or waiting | Check timeouts and dependencies |
Because status shows only a few log lines, the full history comes from journalctl, for example journalctl -u nginx.service -b for the current boot. The two tools are designed to be used together.
Targets, power management and comparison with older tools
systemctl also controls system-wide state through targets, which replace SysVinit runlevels. systemctl get-default shows the boot target, set-default changes it, and isolate switches the running system to another target, stopping units that the new target does not require.
| Task | SysVinit era | systemd era |
|---|---|---|
| Start a service | service nginx start | systemctl start nginx |
| Enable at boot | chkconfig or update-rc.d | systemctl enable nginx |
| Change runlevel | telinit 3 | systemctl isolate multi-user.target |
| Reboot | shutdown -r now | systemctl reboot |
| Suspend | Distribution-specific scripts | systemctl suspend |
Many distributions keep the service command as a compatibility wrapper that forwards to systemctl, so older scripts continue to work.
The same tool manages per-user services with the --user flag, which controls a separate systemd instance running for each logged-in user. Combined with loginctl enable-linger, user services can keep running after logout, a common pattern for rootless containers and personal background jobs. systemctl also lists and controls systemd timers, the modern replacement for many cron jobs, through systemctl list-timers.
Common mistakes
Most systemctl problems in practice come from misunderstanding the state model rather than from bugs in systemd. The following mistakes appear repeatedly in production incidents and support requests.
- Forgetting daemon-reload after editing a unit file, which leaves systemd running the old definition and prints a warning in status.
- Editing vendor units directly in
/usr/lib/systemd/system/, where package updates overwrite the change; drop-ins are the correct method. - Assuming enable starts the service immediately, or that disable prevents manual or dependency-driven starts; only mask does that.
- Using restart where reload suffices, which drops active connections unnecessarily.
- Ignoring the failed state after fixing a problem;
systemctl reset-failedclears it and resets start-rate limits.
In simple terms
A Linux computer runs many background programs, such as a web server, a database or the clock synchronization service. systemctl is the remote control for all of them.
With one command an administrator can turn a program on or off right now, decide whether it should start automatically when the computer boots, or ask why it stopped working. Behind the scenes, systemctl passes these requests to systemd, which does the actual work.
A practical example
An administrator installs a web server on a new Linux virtual machine. The command systemctl enable --now nginx starts it and registers it to start at every boot. After changing the configuration to add a new site, the administrator runs nginx -t and then systemctl reload nginx, so visitors with open connections are not interrupted.
A week later the site is down after a reboot. systemctl status nginx shows failed with an error about an address already in use. The journal reveals that another web server was enabled by mistake. The administrator runs systemctl disable --now apache2, then systemctl restart nginx, and the site is back within a minute, with the cause documented.