Index: src/wp-includes/query.php
===================================================================
--- src/wp-includes/query.php	(revision 26975)
+++ src/wp-includes/query.php	(working copy)
@@ -2673,6 +2673,17 @@
 				$post_type_cap = $post_type;
 		}
 
+		if ( array_key_exists( 'has_password', $q ) ) {
+			$where .= sprintf( " AND $wpdb->posts.post_password %s ''", $q['has_password'] ? '!=' : '=' );
+		}
+
+		if ( isset( $q['post_password'] ) ) {
+			$where .= $wpdb->prepare( " AND $wpdb->posts.post_password = %s", $q['post_password'] );
+			if ( empty( $q['perm'] ) ) {
+				$q['perm'] = 'readable';
+			}
+		}
+
 		if ( 'any' == $post_type ) {
 			$in_search_post_types = get_post_types( array('exclude_from_search' => false) );
 			if ( empty( $in_search_post_types ) )
Index: tests/phpunit/tests/query/results.php
===================================================================
--- tests/phpunit/tests/query/results.php	(revision 26975)
+++ tests/phpunit/tests/query/results.php	(working copy)
@@ -533,4 +533,39 @@
 		$this->assertFalse( $this->q->is_month );
 		$this->assertFalse( $this->q->is_year );
 	}
+
+	function test_post_password() {
+		$post_id1 = (string) $this->factory->post->create( array( 'post_password' => '' ) );
+		$post_id2 = (string) $this->factory->post->create( array( 'post_password' => 'burrito' ) );
+		$post_id3 = (string) $this->factory->post->create( array( 'post_password' => 'burrito' ) );
+
+		// there are too many posts already in the database
+		$args = array( 'post__in' => array( $post_id1, $post_id2, $post_id3 ), 'fields' => 'ids', 'orderby' => 'ID' );
+
+		$result1 = $this->q->query( array_merge( $args, array( 'has_password' => true ) ) );
+		$this->assertEquals( array( $post_id3, $post_id2 ), $result1 );
+		$result2 = $this->q->query( array_merge( $args, array( 'has_password' => false ) ) );
+		$this->assertEquals( array( $post_id1 ), $result2 );
+		$result3 = $this->q->query( array_merge( $args, array( 'has_password' => null ) ) );
+		$this->assertEquals( array( $post_id1 ), $result3 );
+
+		$result4 = $this->q->query( array_merge( $args, array( 'has_password' => true, 'post_password' => '' ) ) );
+		$this->assertEquals( array(), $result4 );
+		$result5 = $this->q->query( array_merge( $args, array( 'has_password' => false, 'post_password' => '' ) ) );
+		$this->assertEquals( array( $post_id1 ), $result5 );
+		$result6 = $this->q->query( array_merge( $args, array( 'has_password' => null, 'post_password' => '' ) ) );
+		$this->assertEquals( array( $post_id1 ), $result6 );
+
+		$result7 = $this->q->query( array_merge( $args, array( 'has_password' => true, 'post_password' => 'burrito' ) ) );
+		$this->assertEquals( array( $post_id3, $post_id2 ), $result7 );
+		$result8 = $this->q->query( array_merge( $args, array( 'has_password' => false, 'post_password' => 'burrito' ) ) );
+		$this->assertEquals( array(), $result8 );
+		$result9 = $this->q->query( array_merge( $args, array( 'has_password' => null, 'post_password' => 'burrito' ) ) );
+		$this->assertEquals( array(), $result9 );
+
+		$result10 = $this->q->query( array_merge( $args, array( 'post_password' => '' ) ) );
+		$this->assertEquals( array( $post_id1 ), $result10 );
+		$result11 = $this->q->query( array_merge( $args, array( 'post_password' => 'burrito' ) ) );
+		$this->assertEquals( array( $post_id3, $post_id2 ), $result11 );
+	}
 }
