diff --git a/src/wp-admin/includes/ms-admin-filters.php b/src/wp-admin/includes/ms-admin-filters.php
index e8952e15b3..02fbf68b3c 100644
--- a/src/wp-admin/includes/ms-admin-filters.php
+++ b/src/wp-admin/includes/ms-admin-filters.php
@@ -38,3 +38,7 @@ add_action( 'network_admin_notices', 'site_admin_notice' );
 // Update Hooks
 add_action( 'network_admin_notices', 'update_nag',      3  );
 add_action( 'network_admin_notices', 'maintenance_nag', 10 );
+
+// Network Admin Hooks
+add_action( 'add_site_option_new_admin_email',    'update_network_option_new_admin_email', 10, 2 );
+add_action( 'update_site_option_new_admin_email', 'update_network_option_new_admin_email', 10, 2 );
diff --git a/src/wp-admin/network/settings.php b/src/wp-admin/network/settings.php
index af37fbcbed..28330e0c4e 100644
--- a/src/wp-admin/network/settings.php
+++ b/src/wp-admin/network/settings.php
@@ -19,6 +19,26 @@ if ( ! current_user_can( 'manage_network_options' ) )
 $title = __( 'Network Settings' );
 $parent_file = 'settings.php';
 
+// Handle network admin email change requests
+if ( ! empty( $_GET[ 'network_admin_hash' ] ) ) {
+	$new_admin_details = get_site_option( 'network_admin_hash' );
+	$redirect = 'settings.php?updated=false';
+	if ( is_array( $new_admin_details ) && hash_equals( $new_admin_details[ 'hash' ], $_GET[ 'network_admin_hash' ] ) && ! empty( $new_admin_details[ 'newemail' ] ) ) {
+		update_site_option( 'admin_email', $new_admin_details[ 'newemail' ] );
+		delete_site_option( 'network_admin_hash' );
+		delete_site_option( 'new_admin_email' );
+		$redirect = 'settings.php?updated=true';
+	}
+	wp_redirect( network_admin_url( $redirect ) );
+	exit;
+} elseif ( ! empty( $_GET['dismiss'] ) && 'new_network_admin_email' == $_GET['dismiss'] ) {
+	check_admin_referer( 'dismiss_new_network_admin_email' );
+	delete_site_option( 'network_admin_hash' );
+	delete_site_option( 'new_admin_email' );
+	wp_redirect( network_admin_url( 'settings.php?updated=true' ) );
+	exit;
+}
+
 add_action( 'admin_head', 'network_settings_add_js' );
 
 get_current_screen()->add_help_tab( array(
@@ -58,7 +78,7 @@ if ( $_POST ) {
 		'upload_space_check_disabled', 'blog_upload_space', 'upload_filetypes', 'site_name',
 		'first_post', 'first_page', 'first_comment', 'first_comment_url', 'first_comment_author',
 		'welcome_email', 'welcome_user_email', 'fileupload_maxk', 'global_terms_enabled',
-		'illegal_names', 'limited_email_domains', 'banned_email_domains', 'WPLANG', 'admin_email',
+		'illegal_names', 'limited_email_domains', 'banned_email_domains', 'WPLANG', 'new_admin_email',
 		'first_comment_email',
 	);
 
@@ -111,10 +131,28 @@ if ( isset( $_GET['updated'] ) ) {
 			<tr>
 				<th scope="row"><label for="admin_email"><?php _e( 'Network Admin Email' ) ?></label></th>
 				<td>
-					<input name="admin_email" type="email" id="admin_email" aria-describedby="admin-email-desc" class="regular-text" value="<?php echo esc_attr( get_site_option( 'admin_email' ) ) ?>" />
+					<input name="new_admin_email" type="email" id="admin_email" aria-describedby="admin-email-desc" class="regular-text" value="<?php echo esc_attr( get_site_option( 'admin_email' ) ) ?>" />
 					<p class="description" id="admin-email-desc">
-						<?php _e( 'This email address will receive notifications. Registration and support emails will also come from this address.' ); ?>
+						<?php _e( 'This address is used for admin purposes. If you change this we will send you an email at your new address to confirm it. <strong>The new address will not become active until confirmed.</strong>' ); ?>
 					</p>
+					<?php
+					$new_admin_email = get_site_option( 'new_admin_email' );
+					if ( $new_admin_email && $new_admin_email != get_site_option( 'admin_email' ) ) : ?>
+						<div class="updated inline">
+						<p><?php
+							printf(
+								/* translators: %s: new network admin email */
+								__( 'There is a pending change of the network admin email to %s.' ),
+								'<code>' . esc_html( $new_admin_email ) . '</code>'
+							);
+							printf(
+								' <a href="%1$s">%2$s</a>',
+								esc_url( wp_nonce_url( network_admin_url( 'settings.php?dismiss=new_network_admin_email' ), 'dismiss_new_network_admin_email' ) ),
+								__( 'Cancel' )
+							);
+						?></p>
+						</div>
+					<?php endif; ?>
 				</td>
 			</tr>
 		</table>
diff --git a/src/wp-includes/ms-functions.php b/src/wp-includes/ms-functions.php
index 03c376836a..53da005cf9 100644
--- a/src/wp-includes/ms-functions.php
+++ b/src/wp-includes/ms-functions.php
@@ -2603,6 +2603,84 @@ function get_subdirectory_reserved_names() {
 }
 
 /**
+ * Send a confirmation request email when a change of network admin email address is attempted.
+ *
+ * The new network admin address will not become active until confirmed.
+ *
+ * @since 4.9.0
+ *
+ * @param string $old_value The old network admin email address.
+ * @param string $value     The proposed new network admin email address.
+ */
+function update_network_option_new_admin_email( $old_value, $value ) {
+	if ( $value == get_site_option( 'admin_email' ) || ! is_email( $value ) ) {
+		return;
+	}
+
+	$hash = md5( $value . time() . mt_rand() );
+	$new_admin_email = array(
+		'hash'     => $hash,
+		'newemail' => $value,
+	);
+	update_site_option( 'network_admin_hash', $new_admin_email );
+
+	$switched_locale = switch_to_locale( get_user_locale() );
+
+	/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
+	$email_text = __( 'Howdy ###USERNAME###,
+
+You recently requested to have the network admin email address on
+your network changed.
+
+If this is correct, please click on the following link to change it:
+###ADMIN_URL###
+
+You can safely ignore and delete this email if you do not want to
+take this action.
+
+This email has been sent to ###EMAIL###
+
+Regards,
+All at ###SITENAME###
+###SITEURL###' );
+
+	/**
+	 * Filters the text of the email sent when a change of network admin email address is attempted.
+	 *
+	 * The following strings have a special meaning and will get replaced dynamically:
+	 * ###USERNAME###  The current user's username.
+	 * ###ADMIN_URL### The link to click on to confirm the email change.
+	 * ###EMAIL###     The proposed new network admin email address.
+	 * ###SITENAME###  The name of the network.
+	 * ###SITEURL###   The URL to the network.
+	 *
+	 * @since 4.9.0
+	 *
+	 * @param string $email_text      Text in the email.
+	 * @param array  $new_admin_email {
+	 *     Data relating to the new network admin email address.
+	 *
+	 *     @type string $hash     The secure hash used in the confirmation link URL.
+	 *     @type string $newemail The proposed new network admin email address.
+	 * }
+	 */
+	$content = apply_filters( 'new_network_admin_email_content', $email_text, $new_admin_email );
+
+	$current_user = wp_get_current_user();
+	$content = str_replace( '###USERNAME###', $current_user->user_login, $content );
+	$content = str_replace( '###ADMIN_URL###', esc_url( network_admin_url( 'settings.php?network_admin_hash=' . $hash ) ), $content );
+	$content = str_replace( '###EMAIL###', $value, $content );
+	$content = str_replace( '###SITENAME###', wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES ), $content );
+	$content = str_replace( '###SITEURL###', network_home_url(), $content );
+
+	wp_mail( $value, sprintf( __( '[%s] New Network Admin Email Address' ), wp_specialchars_decode( get_site_option( 'site_name' ), ENT_QUOTES ) ), $content );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+}
+
+/**
  * Send an email to the old network admin email address when the network admin email address changes.
  *
  * @since 4.9.0
