runlevel: Explanation & Insights

A numbered mode on older Linux systems defining which services run — from single-user maintenance to a full multi-user, networked system.

What It Is

A runlevel is a single number, 0 through 6, that names the one mode a Unix or Linux system is running in right now. That's the whole idea: at any instant the machine is in exactly one runlevel, and that one digit tells you everything about how much of the system is awake. Runlevel 3 is a full multi-user server with networking and no desktop; runlevel 5 is the same plus a graphical login; runlevel 1 is a stripped-down single-user repair mode with almost nothing running; 0 halts the machine and 6 reboots it. Change the number and the system changes state — start the missing services, stop the ones that don't belong.

Think of it as a light switch with exactly seven positions. Most of them turn rooms of the house on in different combinations; one of them turns the whole house off, and one turns it off and straight back on again. You were never in two positions at once. The switch had a single setting, and the init system — the very first process the kernel starts, the one with process ID 1 — was the hand on the switch.

It came out of Unix System V, AT&T's commercial Unix from the early 1980s, which is why the old machinery is still called SysV init today. For roughly thirty years the runlevel was how a Unix box decided what to be at boot. On a modern Linux box it's a fossil — systemd retired the single number years ago — but it's a fossil the system still politely answers to, and that turns out to be the most interesting thing about it.

Note

The numbers were never carved in stone the way the lore suggests. 0, 1, and 6 always meant halt, single-user, and reboot. But 2, 3, 4, and 5 were a free-for-all between distributions — Red Hat put the graphical login on 5, Slackware put X on 4, Debian made 2 through 5 all the same. The "5 is graphical" rule everyone repeats was a Red Hat convention, not a law.

Why It Matters

You will almost never set a runlevel on a server built this decade. So why learn it? Because the words never died. Run who -r on a brand-new Ubuntu or Red Hat box today — or runlevel, on the boxes that still ship it — and you get a number back, confidently, even though that machine has no runlevels at all under the hood. Something is translating, and knowing what — and why — is the difference between trusting that 5 and being baffled by it.

There's also the mechanism to learn from: a directory of symlinks run in numeric order, one of the cleanest ideas in Unix, and once you've seen it you understand half of how Linux still boots, because the compatibility shims kept the shape even after they threw out the engine. And then there's the day you SSH into something genuinely old — an appliance, an embedded board, a server someone forgot in 2009 — where there are no systemd targets at all. There's a runlevel, an /etc/inittab, and a telinit command, and you'll be very glad you know what they do.

How the Number Worked

Here's the part worth slowing down for, because the design is genuinely lovely and it explains everything that came after.

The single process with PID 1 — init — read one file at boot, /etc/inittab, and the most important line in it named the default runlevel: the number to head for once the kernel handed over control. Say it read 3. init would then go looking in a directory named for that level: /etc/rc3.d/.

That directory is the whole trick. It's not full of programs — it's full of symlinks, shortcuts pointing back at the real startup scripts living in /etc/init.d. And every symlink's name follows one rigid rule:

/etc/rc3.d/
  K01nginx      ->  ../init.d/nginx
  S01networking ->  ../init.d/networking
  S10rsyslog    ->  ../init.d/rsyslog
  S20ssh        ->  ../init.d/ssh

The first letter is an order: S means start this, K means kill this (stop it). The two digits are a priority. To enter runlevel 3, init walked the directory in plain alphabetical order — which, because of the numbers, is really numeric order — and ran every K script with stop and every S script with start. That's it. The entire act of "becoming a multi-user server" was a sorted for loop over a folder of named symlinks.

The beauty is what it means to change levels. Each runlevel had its own rcN.d directory. Switching from 3 to 5 didn't tear the machine down and rebuild it; init just diffed the two: stop what shouldn't be running here, start what should. The numbers S01, S10, S20 existed because some services must come up before others — networking before the things that need the network — and a sysadmin tuning boot order was, quite literally, renaming files.

Why

Two digits, so S09 sorts before S10. A whole generation of boot-order bugs came down to someone numbering a script S9 instead of S09, and watching it start after S10 because 9 sorts after 1. The fix was a rename. The bug was the alphabet.

Switching Levels by Hand

You didn't reboot to change runlevel. You told PID 1 to do it, with telinit (historically the same binary as init, just a friendlier name — the tel is for telling init):

telinit 1    # drop to single-user mode — kick everyone off, for repairs
telinit 3    # back up to full multi-user
telinit 6    # reboot
telinit 0    # halt

telinit 1 was the one you reached for when something was badly wrong — it stopped nearly every service and left you alone at a root prompt with the disks mounted — a quiet room for repairs. telinit 0 and telinit 6 are why halt and reboot got numbers at all: shutting down is just another state to transition into, no more special than the others. The machine doesn't switch off because something dramatic happened; it switches off because you asked it to change to the level where nothing runs.

Reading the Number Today

This is where the fossil gets interesting. On any current Linux box, the init system is systemd, and systemd does not have runlevels. It threw out the single number entirely and replaced it with a dependency graph of named units called targetsmulti-user.target, graphical.target — where the system can be pursuing several at once and each one knows what it requires. The full story of that graph belongs on the systemd page; what matters here is that the dial with seven positions is gone.

And yet, ask the machine its runlevel and it answers:

who -r
         run-level 5  2026-06-06 16:34

The machine reported a number it doesn't actually have. (The old runlevel command does the same thing, printing a previous and current level — but on minimal modern installs it's often not even shipped anymore; it lived in the sysvinit-utils package. who -r, which just reads the same boot record the kernel keeps, is the survivor that's always there.) Behind the answer is a thin translation layer systemd ships: target units named runlevel3.target, runlevel5.target and so on, which are nothing but symlinks — the same trick, one more time — pointing at the real targets:

ls -l /lib/systemd/system/runlevel*.target
runlevel0.target -> poweroff.target
runlevel1.target -> rescue.target
runlevel2.target -> multi-user.target
runlevel3.target -> multi-user.target
runlevel4.target -> multi-user.target
runlevel5.target -> graphical.target
runlevel6.target -> reboot.target

So when you ask for the runlevel, systemd looks at which of those aliased targets you're sitting in and hands back the matching digit. The mapping is fixed:

Old runlevel systemd target Meaning
0 poweroff.target Halt
1 rescue.target Single-user repair
2, 3, 4 multi-user.target Full multi-user, no GUI
5 graphical.target Multi-user + graphical login
6 reboot.target Reboot

Notice the squeeze: three old runlevels (2, 3, 4) all collapse onto one target, because systemd never cared about the distinctions Debian and Red Hat used to argue over. So a modern box can essentially only ever report 3 or 5 — the others are transient states it passes through, never rests in.

To see the default the machine boots into — the old /etc/inittab line, reincarnated — ask systemd directly:

systemctl get-default
graphical.target

And the modern telinit 5 is systemctl isolate graphical.target — though telinit still exists as a compatibility command and still works, quietly forwarding your old muscle-memory to the new machinery.

Pro Tip

If who -r says 5 but you're staring at a black console with no desktop, you haven't lost your mind. Someone set the default to multi-user.target (runlevel 3) and then started the display manager by hand, or the GPU driver failed and graphical.target fell back. The number and the reality can disagree, and the number is the one that lies.

Where the Idea Came From

The seven-state model arrived with Unix System V in 1983, AT&T's first Unix sold as a commercial product rather than mailed to universities on tape. Before runlevels, the question "what should this machine be doing right now?" was answered by a single shell script, /etc/rc, that ran top to bottom at boot and that was the end of it — there was no notion of a current state you could move between, no clean way to say "now become a repair console." System V's insight was to make the state a thing the system named and tracked: a number it knew it was in, and could be asked to leave.

That idea — the machine holding an explicit, queryable sense of "what mode am I in" — outlived its own implementation by decades. systemd kept the concept and dropped the integer, because a single number turned out to be too blunt: a real server isn't on a dial from "off" to "graphical," it's a web of services that each depend on others, and a dependency graph describes that honestly where one digit could only approximate it. But the digit was easy to read, easy to type, and easy to remember, and forty years on the commands that print it are still in everyone's fingers. Some fossils are kept around because they're useful. This one's kept around because we never stopped reaching for it.

See Also

  • systemd — what replaced the single number with a graph of targets; the real engine on any modern box
  • sysvinit — the original init that read /etc/inittab and walked the rcN.d symlink farms
  • init system — the broader idea of the PID 1 process that brings the whole machine up
  • /etc/init.d — where the real startup scripts lived that the runlevel symlinks pointed at
  • systemd target — the named, dependency-aware unit that does a runlevel's old job
  • single-user mode — runlevel 1, the quiet room you boot into to fix a broken system

Stuck wondering whether your server is actually in the state you think it is?

CleverUptime watches what's truly running on the box — the services, the load, the memory — and tells you in plain words when reality drifts from what you expected, instead of leaving you to trust a number that might be lying.

Want to see your own server's health right now? One command, no signup, no install.

Check your server →