| Tested on | RHEL 10.2 (Coughlan) — vm1.lab.example |
|---|---|
| Package | libselinux-utils 3.10-1.el10policycoreutils-python-utils 3.10-1.el10selinux-policy-targeted 42.1.18-4.el10_2.1grubby 8.40-83.el10 |
| Applies to | RHEL 9, RHEL 10, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, and Fedora with SELinux |
| Privilege | sudo or root for setenforce, semanage, grubby, and /etc/selinux/config |
| Scope | Check SELinux mode, switch runtime enforcing/permissive with setenforce, mark one domain permissive with semanage, fully disable on RHEL 9+ with grubby and selinux=0, one-boot recovery from the GRUB menu, and safe re-enable with relabel. Does not cover file contexts, booleans, custom policy modules, or full AVC troubleshooting — see linked SELinux guides. |
| Related guides | SELinux modes and file contexts SELinux ports and booleans Remove dot in Linux permissions RHCSA tutorial Patch management and security updates |
SELinux adds Mandatory Access Control on top of normal file permissions. Most RHEL-family systems stay in Enforcing mode. When a service misbehaves, operators search for how to disable SELinux—but the safer path is usually permissive (whole system or one domain) while you read AVC logs and fix labels or booleans.
On RHEL 9 and 10, fully disabling SELinux is a kernel command-line change (selinux=0 through grubby). Setting SELINUX=disabled in /etc/selinux/config alone is not the current method for fully disabling SELinux; use the selinux=0 kernel argument instead.
semanage permissive for one service domain. Use Disabled only when policy work is out of scope and you accept the relabel cost on re-enable.
Quick answer
| Mode | Policy loaded | Violations blocked | How you reach it |
|---|---|---|---|
| Enforcing | Yes | Yes | Default on RHEL; setenforce 1 at runtime |
| Permissive | Yes | No — logged only | setenforce 0, or grubby … --args enforcing=0 |
| Disabled | No | N/A | grubby … --args selinux=0 on RHEL 9+ |
| Goal | Method | Survives reboot? |
|---|---|---|
| Troubleshoot without blocking | sudo setenforce 0 |
No |
| Relax one service only | sudo semanage permissive -a httpd_t |
Yes — until removed |
| Disable completely (RHEL 9+) | sudo grubby --update-kernel ALL --args selinux=0 + reboot |
Yes |
| Force permissive at boot | sudo grubby --update-kernel ALL --args enforcing=0 + reboot |
Yes |
| One-boot recovery | GRUB menu: append enforcing=0 or selinux=0 |
No |
setenforce cannot move the system to Disabled. For label repair, booleans, and restorecon, see SELinux modes and file contexts.
Check the current SELinux mode
Before you change anything, read the active mode and what /etc/selinux/config will apply on the next boot when selinux=0 is not present.
getenforceSample output:
EnforcingAdd detail with sestatus:
sestatusSample output:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcingCompare Current mode with Mode from config file. If they differ, a prior setenforce or a GRUB/grubby kernel argument changed runtime state.
Read the kernel enforce switch when SELinux is loaded:
cat /sys/fs/selinux/enforceSample output when enforcing:
1A value of 0 means permissive. The pseudo-file is absent when SELinux is disabled.
Check whether selinux=0 is already on the default kernel entry:
grubby --info=DEFAULT | grep ^args=Sample output on vm1.lab.example:
args="ro resume=UUID=78531da6-a389-46e8-9bad-267572940826 rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet crashkernel=2G-64G:256M,64G-:512M $tuned_params"When selinux=0 is present in that line, the next boot disables SELinux regardless of SELINUX= in /etc/selinux/config.
The config file still controls enforcing versus permissive when SELinux is enabled:
grep '^SELINUX=' /etc/selinux/configSample output:
SELINUX=enforcingTemporarily disable enforcement with setenforce
Use setenforce when you have shell access and need Permissive or Enforcing until the next reboot. This does not disable SELinux.
Move to permissive mode:
sudo setenforce 0Verify the change:
getenforceSample output:
PermissiveThe kernel switch should read 0:
cat /sys/fs/selinux/enforceSample output:
0Restore enforcing mode when you finish troubleshooting:
sudo setenforce 1Confirm enforcement is back:
getenforceSample output:
EnforcingPermissive still loads policy and keeps labels; it only stops blocking denials. That is why Red Hat recommends it over selinux=0 for diagnosis.
Make one SELinux domain permissive
When a single daemon (for example httpd) triggers denials, mark only its domain permissive while the rest of the system stays enforcing.
Install the Python utils package if semanage is missing (dnf install policycoreutils-python-utils on RHEL-family systems).
Add permissive mode for the Apache domain:
sudo semanage permissive -a httpd_tThe command exits silently when it succeeds. List customized permissive domains:
sudo semanage permissive -lSample output:
Customized Permissive Types
httpd_tYou can also confirm the module name:
semodule -l | grep permissive_httpdSample output:
permissive_httpd_tWith httpd_t permissive, Apache behaves as if SELinux were off for that domain while SSH, databases, and other domains remain enforcing.
Remove the override when policy is fixed:
sudo semanage permissive -d httpd_tSample output:
libsemanage.semanage_direct_remove_key: Removing last permissive_httpd_t module (no other permissive_httpd_t module exists at another priority).Replace httpd_t with the domain from ps -eZ or AVC logs for your service. Port and boolean fixes belong in SELinux ports and booleans.
Disable SELinux completely with selinux=0
On RHEL 9 and later, Red Hat documents full disable through the selinux=0 kernel parameter. I did not leave vm1.lab.example disabled after writing this guide; the steps below match current Red Hat documentation.
Add selinux=0 to every installed kernel:
sudo grubby --update-kernel ALL --args selinux=0Reboot to apply:
sudo rebootAfter reboot, confirm the mode:
getenforceSample output:
DisabledVerify the argument is on the default kernel:
grubby --info=DEFAULT | grep selinuxYou should see selinux=0 in the args= line.
SELINUX=disabled in /etc/selinux/config alone is not the current method for fully disabling SELinux; use the selinux=0 kernel argument instead.
To boot in permissive on every boot while keeping SELinux loaded, use enforcing=0 instead of selinux=0:
sudo grubby --update-kernel ALL --args enforcing=0Remove a persistent kernel argument when you no longer need it:
sudo grubby --update-kernel ALL --remove-args selinux=0Disable SELinux for one boot from GRUB
Use the GRUB editor when you cannot run grubby yet—for example the system will not boot cleanly with enforcing policy.
| Kernel parameter | Effect for that boot |
|---|---|
enforcing=0 |
Permissive (policy still loaded) |
selinux=0 |
SELinux disabled |
Steps:
- Reboot and stop at the GRUB menu before the timer expires.
- Highlight the default entry and press
eto edit. - Move to the line starting with
linuxorlinuxefi. - Append
enforcing=0(permissive) orselinux=0(disabled) to the end of that line. - Press
Ctrl+xto boot with the edited entry.
That change applies to one boot only. For a persistent change on RHEL 9+, use grubby in the previous section.
Re-enable SELinux after it was disabled
Do not jump straight from Disabled to Enforcing when labels may be missing. Red Hat schedules relabeling with fixfiles -F onboot and expects the relabel boot to run in permissive mode so unlabeled objects do not block startup.
Remove the disable kernel argument from all kernels:
sudo grubby --update-kernel ALL --remove-args selinux=0Add enforcing=0 so the next boots stay permissive even if /etc/selinux/config still lists enforcing:
sudo grubby --update-kernel ALL --args enforcing=0Set permissive in the config file:
# /etc/selinux/config
SELINUX=permissive
SELINUXTYPE=targetedSchedule a full relabel on the next boot:
sudo fixfiles -F onbootReboot and let the relabel run while the system stays permissive:
sudo rebootAfter reboot, confirm permissive mode:
getenforceSample output:
PermissiveWhen services behave correctly and relabeling finished, remove the permissive kernel override:
sudo grubby --update-kernel ALL --remove-args enforcing=0Move to enforcing in the config file:
SELINUX=enforcingReboot into enforcing mode:
sudo rebootConfirm enforcement:
getenforceSample output:
EnforcingTroubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
setenforce: SELinux is disabled |
selinux=0 on the kernel cmdline |
Remove with grubby --remove-args selinux=0, reboot, re-enable per the section above |
getenforce still Enforcing after SELINUX=disabled in config |
On RHEL 9 and 10, config alone does not fully disable SELinux | Add selinux=0 with grubby, reboot |
getenforce differs from /etc/selinux/config |
Runtime setenforce or enforcing= on cmdline |
Check grubby --info=DEFAULT and cat /sys/fs/selinux/enforce |
Service works only with setenforce 0 |
Domain or file context mismatch | Use semanage permissive -a domain_t temporarily; fix context per SELinux modes and file contexts |
semanage: command not found |
Python policy utils not installed | Install policycoreutils-python-utils |
| Re-enabled SELinux but many services fail | Relabel boot came up enforcing or relabel was skipped | Add enforcing=0 with grubby, set SELINUX=permissive, run fixfiles -F onboot, reboot, verify, then remove enforcing=0 and set enforcing |
| GRUB one-time edit lost after reboot | Expected — menu edits are not persistent | Use grubby --update-kernel ALL --args selinux=0 or enforcing=0 |
References
- Red Hat Enterprise Linux 10 — Using SELinux
- Changing SELinux states and modes — Red Hat documentation
- SELinux Project wiki
Summary
SELinux on Linux supports Enforcing, Permissive, and Disabled. For short troubleshooting, setenforce 0 moves the running system to permissive without a reboot, and setenforce 1 puts enforcement back. That is the lightest-touch change when you still want policy and labels loaded.
When one daemon is the problem, semanage permissive -a domain_t keeps the rest of the host enforcing—a better default than turning SELinux off system-wide. On RHEL 9 and 10, fully disabling SELinux means grubby --update-kernel ALL --args selinux=0 followed by a reboot. Setting SELINUX=disabled in /etc/selinux/config alone is not the current method for fully disabling SELinux; use the selinux=0 kernel argument instead.
Use a one-time GRUB append (enforcing=0 or selinux=0) when the system will not boot cleanly. To turn SELinux back on, remove selinux=0, add enforcing=0 with grubby, set permissive in the config file, run fixfiles -F onboot, and reboot so relabeling completes in permissive mode. After verification, remove enforcing=0, set enforcing, and reboot again.

