Index: src/js/_enqueues/wp/util.js
===================================================================
--- src/js/_enqueues/wp/util.js	(revision 51132)
+++ src/js/_enqueues/wp/util.js	(working copy)
@@ -115,7 +115,7 @@
 					}
 
 					if ( _.isObject( response ) && ! _.isUndefined( response.success ) ) {
-						deferred[ response.success ? 'resolveWith' : 'rejectWith' ]( this, [response.data] );
+						deferred[ response.success ? 'resolveWith' : 'rejectWith' ]( deferred.jqXHR, [response.data] );
 					} else {
 						deferred.rejectWith( this, [response] );
 					}
Index: src/js/media/models/attachments.js
===================================================================
--- src/js/media/models/attachments.js	(revision 51132)
+++ src/js/media/models/attachments.js	(working copy)
@@ -375,21 +375,15 @@
 	 * passing through the JSON response. We override this to add attributes to
 	 * the collection items.
 	 *
-	 * @since 5.8.0 The response returns the attachments under `response.attachments` and
-	 *              `response.totalAttachments` holds the total number of attachments found.
-	 *
 	 * @param {Object|Array} response The raw response Object/Array.
 	 * @param {Object} xhr
 	 * @return {Array} The array of model attributes to be added to the collection
 	 */
 	parse: function( response, xhr ) {
-		if ( ! _.isArray( response.attachments ) ) {
-			response = [ response.attachments ];
+		if ( ! _.isArray( response ) ) {
+			  response = [response];
 		}
-
-		this.totalAttachments = parseInt( response.totalAttachments, 10 );
-
-		return _.map( response.attachments, function( attrs ) {
+		return _.map( response, function( attrs ) {
 			var id, attachment, newAttributes;
 
 			if ( attrs instanceof Backbone.Model ) {
@@ -409,9 +403,24 @@
 			return attachment;
 		});
 	},
+
+	// Customize fetch so we can extract the total post count from the response headers.
+	fetch: function(options) {
+		var collection = this;
+		var fetched = Backbone.Collection.prototype.fetch.call(this, options)
+			.done( function() {
+				if ( this.hasOwnProperty( 'getResponseHeader' ) ) {
+					collection.totalAttachments = parseInt( this.getResponseHeader( 'X-WP-Total' ), 10 );
+				} else {
+					collection.totalAttachments = 0;
+				}
+			} );
+		return fetched;
+	},
+
 	/**
 	 * If the collection is a query, create and mirror an Attachments Query collection.
-	 * 
+	 *
 	 * @access private
 	 * @param {Boolean} refresh Deprecated, refresh parameter no longer used.
 	 */
Index: src/js/media/models/query.js
===================================================================
--- src/js/media/models/query.js	(revision 51132)
+++ src/js/media/models/query.js	(working copy)
@@ -113,9 +113,7 @@
 		options.remove = false;
 
 		return this._more = this.fetch( options ).done( function( response ) {
-			var attachments = response.attachments;
-
-			if ( _.isEmpty( attachments ) || -1 === this.args.posts_per_page || attachments.length < this.args.posts_per_page ) {
+			if ( _.isEmpty( response ) || -1 === query.args.posts_per_page || response.length < query.args.posts_per_page ) {
 				query._hasMore = false;
 			}
 		});
Index: src/js/media/views/attachments/browser.js
===================================================================
--- src/js/media/views/attachments/browser.js	(revision 51132)
+++ src/js/media/views/attachments/browser.js	(working copy)
@@ -88,6 +88,7 @@
 		}
 
 		this.updateContent();
+		this.updateLoadMoreView();
 
 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
 			this.$el.addClass( 'hide-sidebar' );
@@ -635,11 +636,10 @@
 		});
 
 		view.loadMoreSpinner.show();
-
-		this.collection.more().done( function() {
-			// Within done(), `this` is the returned collection.
+		this.collection.once( 'attachments:received', function() {
 			view.loadMoreSpinner.hide();
 		} );
+		this.collection.more();
 	},
 
 	/**
Index: src/wp-admin/includes/ajax-actions.php
===================================================================
--- src/wp-admin/includes/ajax-actions.php	(revision 51132)
+++ src/wp-admin/includes/ajax-actions.php	(working copy)
@@ -2990,17 +2990,27 @@
 	 * @param array $query An array of query variables.
 	 */
 	$query = apply_filters( 'ajax_query_attachments_args', $query );
-	$query = new WP_Query( $query );
+	$attachments_query = new WP_Query( $query );
 
-	$posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
+	$posts = array_map( 'wp_prepare_attachment_for_js', $attachments_query->posts );
 	$posts = array_filter( $posts );
+	$total_posts = $attachments_query->found_posts;
 
-	$result = array(
-		'attachments'      => $posts,
-		'totalAttachments' => $query->found_posts,
-	);
+	if ( $total_posts < 1 ) {
+		// Out-of-bounds, run the query again without LIMIT for total count.
+		unset( $query['paged'] );
 
-	wp_send_json_success( $result );
+		$count_query = new WP_Query();
+		$count_query->query( $query_args );
+		$total_posts = $count_query->found_posts;
+	}
+
+	$max_pages = ceil( $total_posts / (int) $attachments_query->query['posts_per_page'] );
+
+	header( 'X-WP-Total: ' . (int) $total_posts );
+	header( 'X-WP-TotalPages: ' . (int) $max_pages );
+
+	wp_send_json_success( $posts );
 }
 
 /**
