Index: src/wp-includes/functions.php
===================================================================
--- src/wp-includes/functions.php	(revision 41059)
+++ src/wp-includes/functions.php	(working copy)
@@ -4386,19 +4386,70 @@
  * Determine whether a site is the main site of the current network.
  *
  * @since 3.0.0
+ * @since 4.9.0 The $network_id parameter has been added.
  *
- * @param int $site_id Optional. Site ID to test. Defaults to current site.
+ * @param int $site_id    Optional. Site ID to test. Defaults to current site.
+ * @param int $network_id Optional. Network ID of the network to check for.
+ *                        Defaults to current network.
  * @return bool True if $site_id is the main site of the network, or if not
  *              running Multisite.
  */
-function is_main_site( $site_id = null ) {
-	if ( ! is_multisite() )
+function is_main_site( $site_id = null, $network_id = null ) {
+	if ( ! is_multisite() ) {
 		return true;
+	}
 
-	if ( ! $site_id )
+	if ( ! $site_id ) {
 		$site_id = get_current_blog_id();
+	}
+
+	$site_id = (int) $site_id;
+
+	return $site_id === get_main_site_id( $network_id );
+}
+
+/**
+ * Gets the main site ID.
+ *
+ * @since 4.9.0
+ *
+ * @param int $network_id Optional. The ID of the network for which to get the main site.
+ *                        Defaults to the current network.
+ * @return int The ID of the main site.
+ */
+function get_main_site_id( $network_id = null ) {
+	if ( ! is_multisite() ) {
+		return 1;
+	}
+
+	$network = get_network( $network_id );
+	if ( ! $network ) {
+		return 0;
+	}
+
+	$main_site_id = wp_cache_get( 'network:' . $network->id . ':main_site', 'site-options' );
+	if ( false === $main_site_id ) {
+		$_sites = get_sites( array(
+			'fields'     => 'ids',
+			'number'     => 1,
+			'domain'     => $network->domain,
+			'path'       => $network->path,
+			'network_id' => $network->id,
+		) );
+		$main_site_id = ! empty( $_sites ) ? array_shift( $_sites ) : 0;
 
-	return (int) $site_id === (int) get_network()->site_id;
+		wp_cache_add( 'network:' . $network->id . ':main_site', $main_site_id, 'site-options' );
+	}
+
+	/**
+	 * Filters the main site ID.
+	 *
+	 * @since 4.9.0
+	 *
+	 * @param int $main_site_id The ID of the main site.
+	 * @param int $network_id   The ID of the network for which the main site was detected.
+	 */
+	return (int) apply_filters( 'get_main_site_id', $main_site_id, $network->id );
 }
 
 /**
Index: src/wp-includes/ms-load.php
===================================================================
--- src/wp-includes/ms-load.php	(revision 41059)
+++ src/wp-includes/ms-load.php	(working copy)
@@ -135,7 +135,7 @@
 
 /**
  * Retrieves the closest matching site object by its domain and path.
- * 
+ *
  * This will not necessarily return an exact match for a domain and path. Instead, it
  * breaks the domain and path into pieces that are then used to match the closest
  * possibility from a query.
@@ -426,10 +426,8 @@
 	if ( empty( $current_site->blog_id ) ) {
 		if ( $current_blog->domain === $current_site->domain && $current_blog->path === $current_site->path ) {
 			$current_site->blog_id = $current_blog->blog_id;
-		} elseif ( ! $current_site->blog_id = wp_cache_get( 'network:' . $current_site->id . ':main_site', 'site-options' ) ) {
-			$current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s",
-				$current_site->domain, $current_site->path ) );
-			wp_cache_add( 'network:' . $current_site->id . ':main_site', $current_site->blog_id, 'site-options' );
+		} else {
+			$current_site->blog_id = get_main_site_id( $current_site->id );
 		}
 	}
 
Index: tests/phpunit/tests/multisite/site.php
===================================================================
--- tests/phpunit/tests/multisite/site.php	(revision 41059)
+++ tests/phpunit/tests/multisite/site.php	(working copy)
@@ -741,6 +741,107 @@
 		restore_current_blog();
 	}
 
+	/**
+	 * @ticket 29684
+	 */
+	function test_is_main_site_different_network() {
+		$args = array(
+			'domain' => 'wordpress.org',
+			'path'   => '/',
+		);
+
+		$network_id = self::factory()->network->create( $args );
+
+		$args['site_id'] = $network_id;
+
+		$site_id = self::factory()->blog->create( $args );
+		$other_site_id = self::factory()->blog->create( array_merge( $args, array(
+			'path' => '/foo/',
+		) ) );
+
+		$this->assertTrue( is_main_site( $site_id, $network_id ) );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id() {
+		$this->assertSame( get_current_blog_id(), get_main_site_id() );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id_switched() {
+		$main_site_id = get_current_blog_id();
+
+		$other_site_id = self::factory()->blog->create();
+		switch_to_blog( $other_site_id );
+
+		$result = get_main_site_id();
+
+		restore_current_blog();
+
+		$this->assertSame( $main_site_id, $result );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id_different_network() {
+		$args = array(
+			'domain' => 'wordpress.org',
+			'path'   => '/',
+		);
+
+		$network_id = self::factory()->network->create( $args );
+
+		$args['site_id'] = $network_id;
+
+		$site_id = self::factory()->blog->create( $args );
+		$other_site_id = self::factory()->blog->create( array_merge( $args, array(
+			'path' => '/foo/',
+		) ) );
+
+		$this->assertSame( $site_id, get_main_site_id( $network_id ) );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id_different_network_without_site() {
+		$args = array(
+			'domain' => 'wordpress.org',
+			'path'   => '/',
+		);
+
+		$network_id = self::factory()->network->create( $args );
+
+		$this->assertSame( 0, get_main_site_id( $network_id ) );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id_invalid_network() {
+		$this->assertSame( 0, get_main_site_id( 333 ) );
+	}
+
+	/**
+	 * @ticket 29684
+	 */
+	function test_get_main_site_id_filtered() {
+		add_filter( 'get_main_site_id', array( $this, 'filter_get_main_site_id' ) );
+		$result = get_main_site_id();
+		remove_filter( 'get_main_site_id', array( $this, 'filter_get_main_site_id' ) );
+
+		$this->assertSame( 333, $result );
+	}
+
+	function filter_get_main_site_id( $main_site_id ) {
+		return 333;
+	}
+
 	function test_switch_upload_dir() {
 		$this->assertTrue( is_main_site() );
 
