Index: src/wp-includes/ms-blogs.php
===================================================================
--- src/wp-includes/ms-blogs.php	(revision 28834)
+++ src/wp-includes/ms-blogs.php	(working copy)
@@ -892,3 +892,38 @@
 	wpmu_update_blogs_date();
 }
 
+/**
+ * Handler for updating the blog posts count date when a post is deleted.
+ *
+ * @since 4.0
+ *
+ * @param int $post_id Post ID
+ */
+function _update_posts_count_on_delete( $post_id ) {
+	if ( 'publish' !== get_post_field( 'post_status', $post_id ) ) {
+		return;
+	}
+	
+	update_posts_count();
+}
+
+/**
+ * Handler for updating the blog posts count date when a post status changes.
+ *
+ * @since 4.0
+ *
+ * @param string $new_status The status the post is changing to.
+ * @param string $old_status The status the post is changing from.
+ */
+function _update_posts_count_on_transition_post_status( $new_status, $old_status ) {
+	if ( $new_status === $old_status ) {
+		return;
+	}
+
+	if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
+		return;
+	}
+
+	update_posts_count();
+}
+
Index: src/wp-includes/ms-default-filters.php
===================================================================
--- src/wp-includes/ms-default-filters.php	(revision 28834)
+++ src/wp-includes/ms-default-filters.php	(working copy)
@@ -34,9 +34,10 @@
 
 // Administration
 add_filter( 'term_id_filter', 'global_terms', 10, 2 );
-add_action( 'publish_post', 'update_posts_count' );
+add_action( 'delete_post', '_update_posts_count_on_delete' );
 add_action( 'delete_post', '_update_blog_date_on_post_delete' );
 add_action( 'transition_post_status', '_update_blog_date_on_post_publish', 10, 3 );
+add_action( 'transition_post_status', '_update_posts_count_on_transition_post_status', 10, 2 );
 
 // Counts
 add_action( 'admin_init', 'wp_schedule_update_network_counts');
Index: src/wp-includes/ms-functions.php
===================================================================
--- src/wp-includes/ms-functions.php	(revision 28834)
+++ src/wp-includes/ms-functions.php	(working copy)
@@ -1761,7 +1761,7 @@
  * WordPress MS stores a blog's post count as an option so as
  * to avoid extraneous COUNTs when a blog's details are fetched
  * with get_blog_details(). This function is called when posts
- * are published to make sure the count stays current.
+ * are published or unpublished to make sure the count stays current.
  *
  * @since MU
  */
Index: tests/phpunit/tests/ms.php
===================================================================
--- tests/phpunit/tests/ms.php	(revision 28834)
+++ tests/phpunit/tests/ms.php	(working copy)
@@ -1385,6 +1385,18 @@
 			$GLOBALS['super_admins'] = $old_global;
 		}
 	}
+
+	/**
+	 * @ticket 27952
+	 */
+	function test_posts_count() {
+		$this->factory->post->create();
+		$post2 = $this->factory->post->create();
+		$this->assertEquals( 2, get_blog_details()->post_count );
+
+		wp_delete_post( $post2 );
+		$this->assertEquals( 1, get_blog_details()->post_count );
+	}
 }
 
 endif;
