Index: src/wp-includes/capabilities.php
===================================================================
--- src/wp-includes/capabilities.php	(revision 42637)
+++ src/wp-includes/capabilities.php	(working copy)
@@ -248,6 +248,27 @@
 
 			$caps[] = $post_type->cap->publish_posts;
 			break;
+		case 'manage_option':
+			$caps[] = 'manage_options';
+			$option = $args[0];
+
+			if ( has_filter( "auth_option_{$option}" ) ) {
+				/**
+				 * Filters whether the user is allowed to manage an option.
+				 *
+				 * @since 5.0.0
+				 *
+				 * @param bool   $allowed Whether the user can manage the option. Default false.
+				 * @param string $option  The option name.
+				 * @param int    $user_id User ID.
+				 */
+				$allowed = apply_filters( "auth_option_{$option}", false, $option, $user_id );
+
+				if ( ! $allowed ) {
+					$caps[] = $cap;
+				}
+			}
+			break;
 		case 'edit_post_meta':
 		case 'delete_post_meta':
 		case 'add_post_meta':
Index: src/wp-includes/option.php
===================================================================
--- src/wp-includes/option.php	(revision 42637)
+++ src/wp-includes/option.php	(working copy)
@@ -2032,6 +2032,7 @@
  *
  * @since 2.7.0
  * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
+ * @since 5.0.0 Introduced the `$auth_callback` argument.
  *
  * @global array $new_whitelist_options
  * @global array $wp_registered_settings
@@ -2046,6 +2047,7 @@
  *                                       Valid values are 'string', 'boolean', 'integer', and 'number'.
  *     @type string   $description       A description of the data attached to this setting.
  *     @type callable $sanitize_callback A callback function that sanitizes the option's value.
+ *     @type callable $auth_callback     A callback function to use when performing a manage_option check.
  *     @type bool     $show_in_rest      Whether data associated with this setting should be included in the REST API.
  *     @type mixed    $default           Default value when calling `get_option()`.
  * }
@@ -2058,6 +2060,7 @@
 		'group'             => $option_group,
 		'description'       => '',
 		'sanitize_callback' => null,
+		'auth_callback'     => null,
 		'show_in_rest'      => false,
 	);
 
@@ -2113,6 +2116,9 @@
 	if ( ! empty( $args['sanitize_callback'] ) ) {
 		add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
 	}
+	if ( ! empty( $args['auth_callback'] ) ) {
+		add_filter( "auth_option_{$option_name}", $args['auth_callback'], 10, 3 );
+	}
 	if ( array_key_exists( 'default', $args ) ) {
 		add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
 	}
@@ -2182,6 +2188,11 @@
 			remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
 		}
 
+		// Remove the auth callback if one was set during registration.
+		if ( ! empty( $wp_registered_settings[ $option_name ]['auth_callback'] ) ) {
+			remove_filter( "auth_option_{$option_name}", $wp_registered_settings[ $option_name ]['auth_callback'], 10 );
+		}
+
 		unset( $wp_registered_settings[ $option_name ] );
 	}
 }
