A WordPress mu-plugin (must-use plugin) is a PHP file placed in wp-content/mu-plugins/ that WordPress loads automatically on every request. It cannot be deactivated through the admin and runs before any regular plugin. Use it for code that must always be present: custom hooks, security rules, performance tweaks, or early-loading constants.
Another use case for a mu-plugin is to add extra functions to a plugin or the WP core. For instance, WP STAGING has many filters and hooks that can provide more features to the WP STAGING staging or backup feature. All of these documented filters can be added to a custom mu-plugin.
Quick answer: Drop a
.phpfile with a plugin header intowp-content/mu-plugins/. WordPress picks it up on the next page load, no activation required. Check Plugins → Must-Use Plugins to confirm it loaded.
Introduction to Must-Use Plugins
Mu-plugins live in wp-content/mu-plugins/ (the path is controlled by the WPMU_PLUGIN_DIR constant) and are loaded by WordPress before any plugin in wp-content/plugins/. They do not appear in the standard Plugins list and cannot be deactivated through the admin interface.
The most common scenario where developers reach for a mu-plugin: they have a function or filter that keeps breaking because another admin disables the plugin that contained it, or a plugin update overwrites a customization. A mu-plugin removes both risks at once.
WordPress’s official documentation covers must-use plugins at wordpress.org/documentation/article/must-use-plugins/.
How does a mu-plugin compare to other places you might put the same code?
| Option | Auto-loads | Survives plugin updates | Admin can deactivate | Best for |
|---|---|---|---|---|
| mu-plugin | Yes | Yes | No | Must-run hooks, constants, security rules |
| Regular plugin | Only when active | Yes | Yes | Optional features the site owner controls |
wp-config.php |
Yes | Yes | No | PHP define() constants only |
.htaccess / php.ini |
Yes (server-level) | Yes | No | Server rewrites and PHP ini settings |
Advantages of Mu-Plugins
The main advantage over a regular plugin is tamper-resistance. A regular plugin can be deactivated by any administrator-level user or removed if a credential is compromised. A mu-plugin cannot.
Use a mu-plugin when:
- Code must run even if all regular plugins are deactivated (a maintenance redirect, a security header, a forced HTTPS rule)
- You are registering WP STAGING actions and filters that need to load before the plugin itself initializes
- You manage multiple WordPress sites and want site-specific behavior outside of version-controlled plugins
- You want to apply runtime PHP settings (such as
memory_limit) early in the request lifecycle
Use a regular plugin when:
- The feature should be toggleable by the site owner or a developer
- The functionality ships as an installable product with auto-updates
- You are building something that other plugins discover through
is_plugin_active()
How to Create a WordPress mu-plugin
Step 1: Access Your Site’s Files
Connect to your site via FTP, SFTP, or your web host’s file manager.
Step 2: Locate or Create the mu-plugins Directory
Navigate to wp-content/. Look for the mu-plugins/ folder. If it does not exist, create it. WordPress will start loading PHP files from that directory immediately, with no further configuration.
Step 3: Create Your Plugin File
Create a new PHP file, for example my-mu-plugin.php. Use lowercase letters and hyphens (no spaces) in the filename. The filename appears in Plugins → Must-Use Plugins in the WordPress admin, so choose a descriptive name.
Step 4: Add the Plugin Header and Your Code
Every mu-plugin needs a plugin header comment at the top, the same as a regular plugin. Below is the minimum structure:
<?php
/*
Plugin Name: My Custom Mu-Plugin
Description: A custom must-use plugin to enhance my WordPress site.
Version: 1.0
Author: Mickey Mouse
*/
// Your custom code goes here
Step 5: Upload Your Mu-Plugin
Upload the .php file to wp-content/mu-plugins/ on your server.
Step 6: Verify Activation
There is no activation step. Visit Plugins → Must-Use Plugins in the WordPress admin to confirm the file loaded. If it does not appear, check that the file sits directly in mu-plugins/ (not inside a subdirectory).
Sample Mu-Plugin: Custom Admin Footer Text
Here is a complete, working example that changes the footer text shown at the bottom of every WordPress admin screen:
<?php
/*
Plugin Name: Custom Admin Footer
Description: Changes the footer text in the WordPress admin area.
Version: 1.0
Author: Your Name
*/
add_filter('admin_footer_text', function () {
echo 'Customized by Tony Stark - Powered by WordPress';
});
Common mu-plugin use cases
These are the patterns that come up most often in WP STAGING support tickets and in developer forums:
1. Force debug logging without editing wp-config.php
<?php
/*
Plugin Name: Enable Debug Log
*/
if ( ! defined( 'WP_DEBUG' ) ) {
define( 'WP_DEBUG', true );
}
if ( ! defined( 'WP_DEBUG_LOG' ) ) {
define( 'WP_DEBUG_LOG', true );
}
if ( ! defined( 'WP_DEBUG_DISPLAY' ) ) {
define( 'WP_DEBUG_DISPLAY', false );
}
This is useful on staging or development environments where you want logging active without touching the production wp-config.php. See Enable WordPress Debug Log Mode for the full debugging workflow.
2. Raise the PHP memory limit
The memory_limit ini directive can be changed at runtime via ini_set(), which makes a mu-plugin a clean place to apply it before regular plugins load:
<?php
/*
Plugin Name: Increase Memory Limit
*/
@ini_set( 'memory_limit', '256M' );
Note: some PHP settings are fixed at the server level and cannot be changed via ini_set() at runtime. A full reference to which directives accept runtime changes is at php.net/manual/en/ini.list.php.
3. WP STAGING filter code
WP STAGING exposes documented actions and filters for controlling backup and staging behavior. Because these need to load before WP STAGING itself initializes, a mu-plugin is the right place to register them. Place any add_filter() or add_action() calls in a mu-plugin file and they will always be present regardless of plugin activation order. Browse all available hooks in the WP STAGING actions and filters documentation linked in Related articles below.
4. Forced HTTPS redirect
<?php
/*
Plugin Name: Force HTTPS
*/
add_action( 'template_redirect', function () {
if ( ! is_ssl() ) {
wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 301 );
exit;
}
} );
5. Disable XML-RPC
<?php
/*
Plugin Name: Disable XML-RPC
*/
add_filter( 'xmlrpc_enabled', '__return_false' );
Limitations and gotchas
Before you commit to a mu-plugin, there are a few behaviors worth knowing:
No deactivation or uninstall hook. WordPress never fires deactivate_{plugin} or uninstall_{plugin} for mu-plugins. If your plugin creates options, custom tables, or scheduled cron events, you must clean up those manually: delete the file, then remove the stored data by hand.
Subdirectory loading requires a loader file. WordPress loads only PHP files sitting directly in wp-content/mu-plugins/. If you place code in a subdirectory (for example, mu-plugins/my-plugin/my-plugin.php), WordPress will not pick it up. The standard pattern is to create a thin loader file in the root of mu-plugins/ that calls require_once on the file inside the subdirectory.
Multisite behavior. On a WordPress multisite network, mu-plugins load across every site on every request. There is no per-site toggle. Use is_main_site() or get_current_blog_id() inside the plugin if you need to limit behavior to a specific site in the network.
Load order. Mu-plugins load in ascending alphabetical order by filename, before any plugin in wp-content/plugins/. If the sequence between your mu-plugins matters, prefix filenames: 00-runs-first.php, 10-runs-second.php.
Visibility in the admin. Mu-plugins appear in Plugins → Must-Use Plugins, but show no details unless the plugin header includes Plugin Name, Description, and Version. Always include a header; it makes diagnosis much faster when something goes wrong.
No update mechanism. WordPress has no built-in way to notify you about or update mu-plugins. If you are adapting third-party code for a mu-plugin, you are responsible for tracking updates and applying them manually. For internally developed mu-plugins this is not a concern, but it is worth noting if you are considering converting a community plugin to a mu-plugin.
Where should this code go?
| Scenario | Best location |
|---|---|
PHP constant or define() |
wp-config.php |
| Server rewrite rule | .htaccess |
| PHP memory or execution limit | .htaccess (via php_value) or php.ini |
| Code using WordPress functions that must always run | mu-plugin in wp-content/mu-plugins/ |
| Optional feature the site owner controls | Regular plugin in wp-content/plugins/ |
| Theme-specific output or style changes | Child theme’s functions.php |
A useful rule of thumb: if your code calls any WordPress function (add_filter, get_option, wp_redirect, etc.), put it in a mu-plugin. If it is a bare PHP define() or a tweak that must run before WordPress boots, wp-config.php is the right place.
Conclusion
A mu-plugin is the right tool for code that must always run and cannot risk being switched off accidentally. Setup takes a few minutes: create wp-content/mu-plugins/, add a .php file with a plugin header, and WordPress handles the rest.
If you are developing or testing custom mu-plugin code, we recommend verifying it on a staging environment before deploying to production. WP STAGING makes it straightforward to clone your live site and confirm that the mu-plugin behaves as expected before your changes go live.