Index: src/wp-admin/includes/class-wp-site-health.php
===================================================================
--- src/wp-admin/includes/class-wp-site-health.php	(revision 45887)
+++ src/wp-admin/includes/class-wp-site-health.php	(working copy)
@@ -1289,7 +1289,7 @@
 	 */
 	public function get_test_https_status() {
 		$result = array(
-			'label'       => __( 'Your website is using an active HTTPS connection.' ),
+			'label'       => __( 'Your website is using an active HTTPS connection' ),
 			'status'      => 'good',
 			'badge'       => array(
 				'label' => __( 'Security' ),
@@ -1300,44 +1300,57 @@
 				__( 'An HTTPS connection is needed for many features on the web today, it also gains the trust of your visitors by helping to protecting their online privacy.' )
 			),
 			'actions'     => sprintf(
-				'<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
+				'<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p><p>%s</p>',
 				/* translators: Documentation explaining HTTPS and why it should be used. */
 				esc_url( __( 'https://wordpress.org/support/article/why-should-i-use-https/' ) ),
 				__( 'Learn more about why you should use HTTPS' ),
 				/* translators: accessibility text */
-				__( '(opens in a new tab)' )
+				__( '(opens in a new tab)' ),
+				sprintf(
+					'%s <a target="_blank" href="%s">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
+					__( 'Content-Security-Policy HTTP Header is set to <code>upgrade-insecure-requests</code> when HTTPS will be turned on.' ),
+					/* translators: Documentation explaining Update Insecure Requests CSP. */
+					esc_url( __( 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests' ) ),
+					__( 'Learn more about what this means.' ),
+					/* translators: accessibility text */
+					__( '(opens in a new tab)' )
+				)
 			),
 			'test'        => 'https_status',
 		);
 
-		if ( is_ssl() ) {
-			$wp_url   = get_bloginfo( 'wpurl' );
-			$site_url = get_bloginfo( 'url' );
+		if ( ! wp_is_using_https() ) {
+			$result['status'] = 'recommended';
 
-			if ( 'https' !== substr( $wp_url, 0, 5 ) || 'https' !== substr( $site_url, 0, 5 ) ) {
-				$result['status'] = 'recommended';
+			$result['label'] = __( 'Your website does not use HTTPS' );
 
-				$result['label'] = __( 'Only parts of your site are using HTTPS' );
-
+			if ( is_ssl() ) {
 				$result['description'] = sprintf(
 					'<p>%s</p>',
+					__( 'You are accessing your site with HTTPS, but your site is not correctly configured to use HTTPS.' )
+				);
+			} else {
+				$result['description'] = sprintf(
+					'<p>%s</p>',
+					__( 'Your site is not correctly configured to use HTTPS.' )
+				);
+			}
+
+			if ( wp_is_https_supported() ) {
+				$result['description'] .= sprintf(
+					'<p>%s</p>',
 					sprintf(
 						/* translators: %s: URL to Settings > General to change options. */
-						__( 'You are accessing this website using HTTPS, but your <a href="%s">WordPress Address</a> is not set up to use HTTPS by default.' ),
+						__( 'HTTPS is supported for your website, so you should update your <a href="%s">WordPress Address</a> to use HTTPS by default.' ),
 						esc_url( admin_url( 'options-general.php' ) )
 					)
 				);
-
-				$result['actions'] .= sprintf(
-					'<p><a href="%s">%s</a></p>',
-					esc_url( admin_url( 'options-general.php' ) ),
-					__( 'Update your site addresses' )
+			} else {
+				$result['description'] .= sprintf(
+					'<p>%s</p>',
+					__( 'Talk to your web host about supporting HTTPS for your website.' )
 				);
 			}
-		} else {
-			$result['status'] = 'recommended';
-
-			$result['label'] = __( 'Your site does not use HTTPS' );
 		}
 
 		return $result;
Index: src/wp-includes/default-filters.php
===================================================================
--- src/wp-includes/default-filters.php	(revision 45887)
+++ src/wp-includes/default-filters.php	(working copy)
@@ -332,6 +332,14 @@
 	add_action( 'init', 'wp_cron' );
 }
 
+// HTTPS detection
+add_action( 'init', 'wp_cron_schedule_https_detection' );
+add_action( 'wp_https_detection', 'wp_update_https_detection_errors' );
+add_filter( 'cron_request', 'wp_cron_conditionally_prevent_sslverify', 9999 );
+add_filter( 'the_content', 'wp_replace_insecure_self_links' );
+add_filter( 'widget_text', 'wp_replace_insecure_self_links' );
+add_filter( 'wp_headers', 'wp_add_upgrade_insecure_requests_header' );
+
 // 2 Actions 2 Furious
 add_action( 'do_feed_rdf', 'do_feed_rdf', 10, 1 );
 add_action( 'do_feed_rss', 'do_feed_rss', 10, 1 );
Index: src/wp-includes/https-detection.php
===================================================================
--- src/wp-includes/https-detection.php	(nonexistent)
+++ src/wp-includes/https-detection.php	(working copy)
@@ -0,0 +1,183 @@
+<?php
+/**
+ * HTTPS detection functions.
+ *
+ * @package WordPress
+ * @since 5.4.0
+ */
+
+/**
+ * Checks whether the website is using HTTPS.
+ *
+ * This is based on whether the home and site URL are using HTTPS.
+ *
+ * @since 5.4.0
+ *
+ * @return bool True if using HTTPS, false otherwise.
+ */
+function wp_is_using_https() {
+	if ( 'https' !== wp_parse_url( home_url(), PHP_URL_SCHEME ) ) {
+		return false;
+	}
+
+	if ( 'https' !== wp_parse_url( site_url(), PHP_URL_SCHEME ) ) {
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Checks whether HTTPS is supported for the server and domain.
+ *
+ * @since 5.4.0
+ *
+ * @return bool True if HTTPS is supported, false otherwise.
+ */
+function wp_is_https_supported() {
+	$https_detection_errors = get_option( 'https_detection_errors' );
+
+	// If option has never been set by the Cron hook before, run it on-the-fly as fallback.
+	if ( false === $https_detection_errors ) {
+		wp_update_https_detection_errors();
+
+		$https_detection_errors = get_option( 'https_detection_errors' );
+	}
+
+	// If there are no detection errors, HTTPS is supported.
+	return empty( $https_detection_errors );
+}
+
+/**
+ * Runs a remote HTTPS request to detect whether HTTPS supported, and stores potential errors.
+ *
+ * This internal function is called by a regular Cron hook to ensure HTTPS support is detected and maintained.
+ *
+ * @since 5.4.0
+ * @access private
+ */
+function wp_update_https_detection_errors() {
+	$support_errors = new WP_Error();
+
+	$response = wp_remote_request(
+		home_url( '/', 'https' ),
+		array(
+			'headers'   => array(
+				'Cache-Control' => 'no-cache',
+			),
+			'sslverify' => true,
+		)
+	);
+
+	if ( is_wp_error( $response ) ) {
+		$unverified_response = wp_remote_request(
+			home_url( '/', 'https' ),
+			array(
+				'headers'   => array(
+					'Cache-Control' => 'no-cache',
+				),
+				'sslverify' => false,
+			)
+		);
+
+		if ( is_wp_error( $unverified_response ) ) {
+			$support_errors->add(
+				$unverified_response->get_error_code(),
+				$unverified_response->get_error_message()
+			);
+		} else {
+			$support_errors->add(
+				'ssl_verification_failed',
+				$response->get_error_message()
+			);
+		}
+
+		$response = $unverified_response;
+	}
+
+	if ( ! is_wp_error( $response ) && 200 !== wp_remote_retrieve_response_code( $response ) ) {
+		$support_errors->add( 'response_error', wp_remote_retrieve_response_message( $response ) );
+	}
+
+	update_option( 'https_detection_errors', $support_errors->errors );
+}
+
+/**
+ * Schedules the Cron hook for detecting HTTPS support.
+ *
+ * @since 5.4.0
+ * @access private
+ */
+function wp_cron_schedule_https_detection() {
+	if ( ! wp_next_scheduled( 'wp_https_detection' ) ) {
+		wp_schedule_event( time(), 'twicedaily', 'wp_https_detection' );
+	}
+}
+
+/**
+ * Disables SSL verification if the 'cron_request' arguments include an HTTPS URL.
+ *
+ * This prevents an issue if HTTPS breaks, where there would be a failed attempt to verify HTTPS.
+ *
+ * @since 5.4.0
+ * @access private
+ *
+ * @param array $request The Cron request arguments.
+ * @return array $request The filtered Cron request arguments.
+ */
+function wp_cron_conditionally_prevent_sslverify( $request ) {
+	if ( 'https' === wp_parse_url( $request['url'], PHP_URL_SCHEME ) ) {
+		$request['args']['sslverify'] = false;
+	}
+	return $request;
+}
+
+/**
+ * Replaces insecure HTTP URLs with HTTPS URLs in the given content.
+ *
+ * @since 5.4.0
+ *
+ * @param string $content Content to replace insecure URLs in.
+ * @return string Modified content.
+ */
+function wp_replace_insecure_self_links( $content ) {
+	if ( ! wp_is_using_https() ) {
+		return $content;
+	}
+
+	return str_replace( home_url( '', 'http' ), home_url( '', 'https' ), $content );
+}
+
+/**
+ * Adds Upgrade-Insecure-Requests header.
+ * Allows filtering to use Content-Security-Policy-Report-Only instead.
+ *
+ * Upgrades insecure requests, such as scripts and images, to HTTPS.
+ * There's no fallback if the upgraded HTTPS request fails.
+ * Navigational third-party resources are not upgraded.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade-Insecure-Requests
+ * @param array $headers The response headers.
+ * @return array $headers The filtered response headers.
+ */
+function wp_add_upgrade_insecure_requests_header( $headers ) {
+    if ( ! wp_is_using_https() ) {
+        return $headers;
+    }
+
+    /**
+     * Filters the report URI for Content-Security-Policy-Report-Only header. If this is set then only CSPRO header is added.
+     *
+     * @since 5.4.0
+     *
+     * @param string $report_only_endpoint Content-Security-Policy-Report-Only report URI. Default is null.
+     */
+    $report_only_endpoint = apply_filters( 'wp_csp_report_only_endpoint', null );
+
+    if ( $report_only_endpoint && is_string( $report_only_endpoint ) ) {
+        $headers['Content-Security-Policy-Report-Only'] = "default-src https:; report-uri $report_only_endpoint";
+    } else {
+        $headers['Content-Security-Policy'] = 'upgrade-insecure-requests';
+    }
+    return $headers;
+}
Index: src/wp-settings.php
===================================================================
--- src/wp-settings.php	(revision 45887)
+++ src/wp-settings.php	(working copy)
@@ -163,6 +163,7 @@
 require( ABSPATH . WPINC . '/theme.php' );
 require( ABSPATH . WPINC . '/class-wp-theme.php' );
 require( ABSPATH . WPINC . '/template.php' );
+require( ABSPATH . WPINC . '/https-detection.php' );
 require( ABSPATH . WPINC . '/class-wp-user-request.php' );
 require( ABSPATH . WPINC . '/user.php' );
 require( ABSPATH . WPINC . '/class-wp-user-query.php' );
