
September 11, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Linux process management and signals decide whether your web stack stays online or silently eats RAM until the server locks up. Every PHP-FPM worker, MySQL connection, Redis client, and Laravel queue job is a process with a PID, parent, state, and signal handlers. On real client projects I maintain on Ubuntu 22/24, most "mysterious" outages trace back to orphaned workers, wrong stop signals, or a full process table. This guide covers the commands, signals, and systemd patterns you actually use when debugging production servers — not textbook theory.
ps and top, change priority with nice, and stop or restart them using numeric signals via kill. Signal 15 (SIGTERM) asks politely; signal 9 (SIGKILL) forces immediate termination.If you run Laravel, WordPress, or custom APIs on Linux, process hygiene belongs in the same checklist as automated database backups and firewall rules. The kernel tracks each executable as a process tree rooted at PID 1 — historically init, now systemd on Ubuntu. Child processes inherit environment variables, file descriptors, and signal disposition from their parent. When a parent dies without reaping children, you get zombies. When children ignore SIGTERM, deploy scripts hang. Both scenarios show up weekly on shared EC2 boxes where I run Deployer 7 releases.
What is Linux process management and how does the process lifecycle work?
A process is a running instance of a program. The kernel assigns it a unique Process ID (PID), a Parent PID (PPID), a user ID, a current state, and resource counters for CPU time and memory (RSS/VMS). Understanding that model is the foundation of Linux process management and signals.
Processes move through several states during their lifetime:
- Running (R): executing on a CPU core or ready in the run queue.
- Interruptible sleep (S): waiting for I/O — disk, network, or a lock.
- Uninterruptible sleep (D): blocked on hardware; cannot be killed until the driver returns.
- Stopped (T): paused by SIGSTOP or a debugger.
- Zombie (Z): exited but not yet reaped by the parent; holds a slot in the process table.
Process identifiers you should know
Every troubleshooting session starts with three numbers:
- PID — the process itself; you pass this to
kill. - PPID — who spawned it; useful when hunting runaway shell scripts.
- PGID / SID — process group and session ID; job control and daemon grouping rely on these.
On a typical Laravel host, systemd (PID 1) starts apache2 or nginx. The web server forks php-fpm master, which manages worker pools. Queue workers started via supervisor or systemd units sit alongside cron-triggered php artisan schedule:run children. That tree is what you map when CPU spikes at 3 AM.
How do you list, monitor, and control processes on a Linux server?
Command-line tools are still the fastest path when SSH is your only interface. I reach for these daily on production boxes — often before opening a Netdata monitoring dashboard.
Listing processes with ps and pgrep
# Full process list, human-readable
ps aux
# Tree view — see parent/child relationships
ps auxf
# Find PHP-FPM workers for pool www
ps aux | grep '[p]hp-fpm: pool www'
# Return only PIDs matching a pattern
pgrep -a php-fpm
pgrep -u www-data -a artisan The ps aux columns matter: %CPU, %MEM, VSZ, RSS, STAT, and START. A worker stuck in D state usually means storage or NFS trouble, not application logic. High RSS on a single PHP worker often signals a memory leak in a long-running queue job.
Live monitoring with top and htop
# Default live view; press M to sort by memory, P by CPU
top
# Better UI — install once per server
sudo apt install htop
htop Inside top, press k to send a signal to a PID without leaving the TUI. For sustained observation, I prefer htop because it shows the tree and per-process thread counts. Pair this with log rotation checks when disk I/O wait climbs — slow logs often correlate with processes stuck in uninterruptible sleep.
Changing priority with nice and renice
# Start a backup script at lower priority (range -20 to 19; higher nice = lower priority)
nice -n 10 mysqldump -u backup myapp > /var/backups/myapp.sql
# Lower priority of an already-running PID
sudo renice +5 -p 4821 On budget VPS hosts common in Nepal (Rs 1,500–3,000/month, ~USD 11–22), CPU contention between MySQL and PHP-FPM is routine. Bumping backup jobs to nice 10 or 15 keeps checkout flows responsive during nightly dumps.
What are Linux signals and which ones matter for production servers?
Signals are asynchronous notifications sent to processes. They can come from the kernel, another process, or the terminal driver. The canonical reference is the Linux manual page signal(7) on man7.org. Each signal has a default action: terminate, ignore, stop, or continue.
A process may register a handler with signal() or sigaction(). Until then, the default applies. That distinction explains why kill -9 works when kill -15 does not — SIGKILL and SIGSTOP cannot be caught or ignored.
Essential signals for web developers and sysadmins
| Signal | Number | Default action | Typical use |
|---|---|---|---|
| SIGHUP | 1 | Terminate | Reload config without full restart — Apache graceful, some daemons |
| SIGINT | 2 | Terminate | Ctrl+C in terminal; interrupt foreground scripts |
| SIGQUIT | 3 | Core dump + terminate | Debug crashes; rarely used in production automation |
| SIGKILL | 9 | Terminate (forced) | Last resort for stuck workers; no cleanup |
| SIGTERM | 15 | Terminate | Default for kill and systemctl stop; preferred graceful stop |
| SIGUSR1 | 10 | Terminate | nginx reopen logs; PHP-FPM status on some builds |
| SIGSTOP | 19 | Stop | Pause process; cannot be ignored |
| SIGCONT | 18 | Continue | Resume after SIGSTOP |
Sending signals with kill, killall, and pkill
# Default SIGTERM (15) — ask process to exit cleanly
kill 3847
# Explicit signal by name or number
kill -TERM 3847
kill -15 3847
kill -HUP 892 # reload nginx master after cert renewal
# Kill all processes matching a name — use carefully in production
pkill -TERM -f 'artisan queue:work'
killall -TERM php-fpm8.3
# Nuclear option — only when TERM failed and service is wedged
kill -9 3847 Always try SIGTERM first. I've seen corrupted MySQL tables and half-written uploads after teams reached for SIGKILL during a routine deploy. Laravel queue workers handle SIGTERM correctly when --max-time and graceful shutdown are configured; systemd sends TERM first, then KILL after TimeoutStopSec.
How does systemd fit into Linux process management on Ubuntu?
Modern Ubuntu servers delegate long-running service control to systemd. Units define how processes start, restart, and stop. The official systemd.service documentation describes directives that map directly to signal behaviour.
If you already read my notes on managing services with systemd, this section connects that article to signal-level detail.
Unit files and stop behaviour
# /etc/systemd/system/laravel-worker@.service
[Unit]
Description=Laravel Queue Worker %i
After=network.target mysql.service redis.service
[Service]
User=www-data
WorkingDirectory=/var/www/myapp/current
ExecStart=/usr/bin/php artisan queue:work redis --sleep=3 --max-time=3600
Restart=always
RestartSec=5
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30
SendSIGKILL=yes
[Install]
WantedBy=multi-user.target Key directives:
- KillSignal — which signal systemd sends on
stop(default SIGTERM). - TimeoutStopSec — wait time before escalation.
- SendSIGKILL — whether to send SIGKILL after timeout.
- KillMode —
control-groupkills all processes in the cgroup;mixedsends TERM to main, KILL to remaining.
# Reload unit after editing
sudo systemctl daemon-reload
# Graceful stop — sends SIGTERM per unit file
sudo systemctl stop laravel-worker@1
# Check exit status and last signal
systemctl status laravel-worker@1
journalctl -u laravel-worker@1 -n 50 --no-pager On sister sites I deploy with Deployer 7 and GitLab CI, the post-deploy step reloads PHP-FPM — not restart — to avoid dropping in-flight requests:
# Sends SIGUSR2 to php-fpm master for graceful worker reload
sudo systemctl reload php8.3-fpm That pattern matters for opcache invalidation after symlink swap. A full restart sends SIGTERM to every worker mid-request.
How do you troubleshoot stuck processes on a Laravel or PHP-FPM host?
Production debugging follows a repeatable sequence. I use it on legal-tech portals, eCommerce carts, and booking systems where downtime has direct revenue impact.
Step-by-step production triage
- Identify the offender. Run
toporps aux --sort=-%cpu | head -20. Note PID, user, and runtime. - Inspect the process. Use
ls -l /proc/PID/fdfor open files. Read/proc/PID/statusfor state and parent. - Check logs. Correlate with PHP-FPM slow log, Laravel log, and MySQL slow query log.
- Send SIGTERM.
kill -TERM PIDorsystemctl stop servicename. Wait 30 seconds. - Verify exit. Confirm PID gone via
ps -p PID. If still running inDstate, investigate disk — not signals. - Escalate to SIGKILL only if needed. Document why; check data integrity after.
PHP-FPM pool exhaustion
When all pm.max_children workers are busy, new requests queue or time out. Symptoms look like application failure but are pure process limits.
# Count active php-fpm workers
ps -eo pid,user,cmd | grep 'php-fpm: pool' | wc -l
# Check pool config
grep -E 'pm\.(max_children|start_servers|min_spare|max_spare)' /etc/php/8.3/fpm/pool.d/www.conf
# Graceful reload after config change
sudo systemctl reload php8.3-fpm On a booking platform like Adventure Third Pole Trek, peak season traffic can saturate workers if cron, queues, and web traffic share one pool. Splitting pools — www for HTTP, internal for CLI — is a pattern I've used on busy Laravel + Livewire apps.
Zombie and orphan cleanup
# List zombie processes
ps aux | awk '$8 ~ /Z/ { print }'
# Find parent of zombie PID 9912
ps -o ppid= -p 9912
# Restart parent service — zombies clear when parent calls wait()
sudo systemctl restart php8.3-fpm Zombies consume almost no CPU or RAM. They still occupy a row in the process table. Thousands of zombies can block new forks — rare but catastrophic. Fix the parent, not the zombie child.
What are common process management mistakes on shared hosting and VPS servers?
Most failures I see are operational, not kernel bugs. Small teams running law-firm portals or WooCommerce shops on single VPS instances repeat the same patterns.
Running everything as root
Processes started by root and left daemonised become hard to trace. Cron jobs that call php artisan as root create log files owned by root. PHP-FPM then cannot write to them. Use dedicated users per app and align with Linux file permission basics.
Ignoring ulimit and pid_max
# Current limits for shell session
ulimit -a
# System-wide max PIDs
cat /proc/sys/kernel/pid_max
# Open files limit — critical for MySQL and nginx
ulimit -n High-traffic eCommerce during festival season in Nepal can exhaust file descriptors when connection pooling is misconfigured. Raise limits in /etc/security/limits.conf and systemd unit files — not only in interactive shells.
Cron without flock or systemd timers
Overlapping cron invocations spawn duplicate queue workers or double billing scripts. Prefer systemd timers or wrap commands:
# Prevent overlapping schedule runs
* * * * * flock -n /tmp/artisan-schedule.lock /usr/bin/php /var/www/app/artisan schedule:run See cron job scheduling patterns for timer-based alternatives that integrate cleanly with signal-aware unit files.
Skipping post-deploy PHP-FPM reload
After Deployer symlink swap, stale opcache serves old bytecode. New code paths never run. Workers keep old bootstrap. A reload costs seconds; a full restart drops active sessions. This belongs in every deploy checklist alongside testing and optimization gates.
For teams without in-house ops capacity, structured Linux system administration covers process tuning, systemd units, and incident response. Long-term maintainers often pair that with support and maintenance retainers so queue workers and PHP pools get reviewed before peak traffic.
Key Takeaways
- Every running service is a process tree — map PIDs before you kill anything.
- Send SIGTERM first; reserve SIGKILL for wedged processes after a documented wait.
- Use
systemctlwith properKillSignalandTimeoutStopSecfor Laravel workers and PHP-FPM. - State
Dmeans disk or driver trouble — signals will not fix it. - Reload PHP-FPM after deploys; restart only when pool config changes require it.
- Monitor zombie counts and file descriptor limits before they block new forks.
People Also Ask
What is the difference between a process and a thread on Linux?
A process is an independent program instance with its own PID and virtual memory space. Threads share the same PID's memory but have separate stack and register state. PHP-FPM uses multi-process workers, not threads — each worker is a separate process you can signal individually.
Why does kill -9 sometimes fail?
SIGKILL is handled directly by the kernel and cannot be blocked by user-space code. If kill -9 appears to fail, the PID may already have exited, you lack permission (try sudo), or the process is stuck in uninterruptible D state waiting on kernel I/O. In the D case, only fixing the underlying I/O problem resolves it.
How do I find which process is using a specific port?
Run sudo ss -tlnp 'sport = :443' or sudo lsof -i :443. Both show the PID and program name bound to the port. This is faster than guessing which nginx or Apache instance holds the socket when multiple sites share a server.
Does systemd replace kill and ps commands?
No. Systemd manages service lifecycle and sends signals on your behalf, but ps, top, and kill remain essential for debugging processes systemd did not start — manual scripts, orphaned cron children, and container sidecars. Treat systemd as the preferred controller for declared services and CLI tools for everything else.
Put Linux process management and signals into your runbook
Stable production servers depend on predictable process behaviour. Know your signal order: TERM, wait, then KILL. Configure systemd units for queue workers. Reload PHP-FPM after every deploy. Correlate ps output with application logs before you terminate PIDs. These habits prevent the 2 AM fire drills I still see on otherwise well-built Laravel and WordPress stacks.
Need help tuning PHP-FPM pools, writing systemd units, or cleaning up a overloaded VPS? Review the portfolio for production deployments, try the JSON formatter when debugging API worker payloads, or contact us for hands-on Linux process management and signals support on your server.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

