Disable SELinux in Linux (Runtime, Permissive, and Permanent)

Deepak Prasad
Tested on RHEL 10.2 (Coughlan) — vm1.lab.example
Package libselinux-utils 3.10-1.el10
policycoreutils-python-utils 3.10-1.el10
selinux-policy-targeted 42.1.18-4.el10_2.1
grubby 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.

IMPORTANT
Disabling SELinux removes MAC protection and can leave stale labels if you turn it back on later. Prefer Permissive for troubleshooting, or 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.

bash
getenforce

Sample output:

output
Enforcing

Add detail with sestatus:

bash
sestatus

Sample output:

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:          enforcing

Compare 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:

bash
cat /sys/fs/selinux/enforce

Sample output when enforcing:

output
1

A 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:

bash
grubby --info=DEFAULT | grep ^args=

Sample output on vm1.lab.example:

output
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:

bash
grep '^SELINUX=' /etc/selinux/config

Sample output:

output
SELINUX=enforcing

Temporarily 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:

bash
sudo setenforce 0

Verify the change:

bash
getenforce

Sample output:

output
Permissive

The kernel switch should read 0:

bash
cat /sys/fs/selinux/enforce

Sample output:

output
0

Restore enforcing mode when you finish troubleshooting:

bash
sudo setenforce 1

Confirm enforcement is back:

bash
getenforce

Sample output:

output
Enforcing

Permissive 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:

bash
sudo semanage permissive -a httpd_t

The command exits silently when it succeeds. List customized permissive domains:

bash
sudo semanage permissive -l

Sample output:

output
Customized Permissive Types

httpd_t

You can also confirm the module name:

bash
semodule -l | grep permissive_httpd

Sample output:

output
permissive_httpd_t

With 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:

bash
sudo semanage permissive -d httpd_t

Sample output:

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:

bash
sudo grubby --update-kernel ALL --args selinux=0

Reboot to apply:

bash
sudo reboot

After reboot, confirm the mode:

bash
getenforce

Sample output:

output
Disabled

Verify the argument is on the default kernel:

bash
grubby --info=DEFAULT | grep selinux

You should see selinux=0 in the args= line.

NOTE
On RHEL 9 and 10, setting 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:

bash
sudo grubby --update-kernel ALL --args enforcing=0

Remove a persistent kernel argument when you no longer need it:

bash
sudo grubby --update-kernel ALL --remove-args selinux=0

Disable 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:

  1. Reboot and stop at the GRUB menu before the timer expires.
  2. Highlight the default entry and press e to edit.
  3. Move to the line starting with linux or linuxefi.
  4. Append enforcing=0 (permissive) or selinux=0 (disabled) to the end of that line.
  5. Press Ctrl+x to 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:

bash
sudo grubby --update-kernel ALL --remove-args selinux=0

Add enforcing=0 so the next boots stay permissive even if /etc/selinux/config still lists enforcing:

bash
sudo grubby --update-kernel ALL --args enforcing=0

Set permissive in the config file:

text
# /etc/selinux/config
SELINUX=permissive
SELINUXTYPE=targeted

Schedule a full relabel on the next boot:

bash
sudo fixfiles -F onboot

Reboot and let the relabel run while the system stays permissive:

bash
sudo reboot

After reboot, confirm permissive mode:

bash
getenforce

Sample output:

output
Permissive

When services behave correctly and relabeling finished, remove the permissive kernel override:

bash
sudo grubby --update-kernel ALL --remove-args enforcing=0

Move to enforcing in the config file:

text
SELINUX=enforcing

Reboot into enforcing mode:

bash
sudo reboot

Confirm enforcement:

bash
getenforce

Sample output:

output
Enforcing

Troubleshooting

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


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.


Frequently Asked Questions

1. Can setenforce disable SELinux completely?

No. setenforce only toggles between Enforcing and Permissive while SELinux stays loaded. On RHEL 9 and later, fully disable SELinux across reboots with grubby --update-kernel ALL --args selinux=0 and reboot, or pass selinux=0 once from the GRUB menu.

2. What is the difference between permissive and disabled?

Permissive keeps SELinux policy and file labels active but logs denials without blocking. Disabled unloads SELinux enforcement through the selinux=0 kernel parameter on current RHEL. Red Hat recommends permissive for troubleshooting instead of disabling.

3. Do I need a reboot to disable SELinux permanently?

Yes. On RHEL 9 and 10, add selinux=0 to all installed kernels with grubby, reboot, and confirm with getenforce. Runtime setenforce changes alone never survive reboot and never reach Disabled.

4. What happens if I re-enable SELinux after it was disabled?

Remove selinux=0 with grubby, add enforcing=0 with grubby, set SELINUX=permissive in /etc/selinux/config, run fixfiles -F onboot, and reboot so the relabel boot stays permissive. After relabeling completes and you verify services, remove enforcing=0 with grubby, set SELINUX=enforcing, and reboot again.

5. Can I relax SELinux for one service only?

Yes. Use semanage permissive -a domain_t to mark one domain permissive while the rest of the system stays enforcing. That is usually safer than setenforce 0 or selinux=0 on every boot.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration