diff --git a/core/modules/node/lib/Drupal/node/NodeAccessController.php b/core/modules/node/lib/Drupal/node/NodeAccessController.php
index cee9228..96dd62d 100644
--- a/core/modules/node/lib/Drupal/node/NodeAccessController.php
+++ b/core/modules/node/lib/Drupal/node/NodeAccessController.php
@@ -43,6 +43,11 @@ protected function checkAccess(EntityInterface $node, $operation, $langcode, Use
       $uid = $node->getTranslation($langcode, FALSE)->uid->value;
     }
 
+    // Ensure users with permissions to view any unpublished content can do so.
+    if ($operation == 'view' && !$status && user_access('view any unpublished content', $account)) {
+      return TRUE;
+    }
+
     // Check if authors can view their own unpublished nodes.
     if ($operation === 'view' && !$status && user_access('view own unpublished content', $account)) {
 
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
index 73b3a44..284e1d5 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
@@ -62,9 +62,23 @@ function testNodeAccess() {
     $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE), $node4, $web_user4);
     $this->assertNodeAccess(array('view' => FALSE), $node4, $web_user5);
 
+    // Ensures user with 'view any unpublished content' can do so.
+    $web_user6 = $this->drupalCreateUser(array('access content', 'view any unpublished content'));
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE), $node4, $web_user6);
+
+    // Ensures the more granular view unpublished permissions are respected.
+    $web_user7 = $this->drupalCreateUser(array('access content'));
+    $web_user8 = $this->drupalCreateUser(array('access content', 'view unpublished page content'));
+    $web_user9 = $this->drupalCreateUser(array('access content', 'view unpublished article content'));
+    $node5 = $this->drupalCreateNode(array('type' => 'page', 'status' => 0));
+    $node6 = $this->drupalCreateNode(array('type' => 'article', 'status' => 0));
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE), $node5, $web_user8);
+    $this->assertNodeAccess(array('view' => FALSE, 'update' => FALSE), $node5, $web_user9);
+    $this->assertNodeAccess(array('view' => FALSE, 'update' => FALSE), $node6, $web_user8);
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE), $node6, $web_user9);
+
     // Tests the default access provided for a published node.
-    $node5 = $this->drupalCreateNode();
-    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $node5, $web_user3);
+    $node7 = $this->drupalCreateNode();
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $node7, $web_user3);
   }
-
 }
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index 139b2d2..1e51eac 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -492,7 +492,9 @@ function node_admin_nodes() {
     ->extend('Drupal\Core\Database\Query\TableSortExtender');
   node_build_filter_query($query);
 
-  if (!user_access('bypass node access')) {
+  // If the user is allowed to bypass node access or if the user is allowed to
+  // view all unpublished content, then we don't need to add any extra checks.
+  if (!user_access('bypass node access') && !user_access('view any unpublished content')) {
     // If the user is able to view their own unpublished nodes, allow them
     // to see these in addition to published nodes. Check that they actually
     // have some unpublished nodes to view before adding the condition.
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 0d92454..5fe4207 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1238,6 +1238,9 @@ function node_permission() {
     'view own unpublished content' => array(
       'title' => t('View own unpublished content'),
     ),
+    'view any unpublished content' => array(
+      'title' => t('View any unpublished content'),
+    ),
     'view all revisions' => array(
       'title' => t('View all revisions'),
     ),
@@ -1878,7 +1881,9 @@ function node_revision_list(EntityInterface $node) {
 function node_get_recent($number = 10) {
   $query = db_select('node', 'n');
 
-  if (!user_access('bypass node access')) {
+  // If the user is allowed to bypass node access or if the user is allowed to
+  // view all unpublished content, then we don't need to add any extra checks.
+  if (!user_access('bypass node access') && !user_access('view any unpublished content')) {
     // If the user is able to view their own unpublished nodes, allow them
     // to see these in addition to published nodes. Check that they actually
     // have some unpublished nodes to view before adding the condition.
@@ -2550,6 +2555,10 @@ function node_node_access($node, $op, $account) {
 
   $configured_types = node_permissions_get_configured_types();
   if (isset($configured_types[$type])) {
+    if ($op == 'view' && user_access('view unpublished ' . $type . ' content', $account)) {
+      return NODE_ACCESS_ALLOW;
+    }
+
     if ($op == 'create' && user_access('create ' . $type . ' content', $account)) {
       return NODE_ACCESS_ALLOW;
     }
@@ -2582,6 +2591,9 @@ function node_node_access($node, $op, $account) {
 function node_list_permissions($type) {
   // Build standard list of node permissions for this type.
   $perms = array(
+    "view unpublished $type->type content" => array(
+      'title' => t('%type_name: View unpublished', array('%type_name' => $type->name)),
+    ),
     "create $type->type content" => array(
       'title' => t('%type_name: Create new content', array('%type_name' => $type->name)),
     ),
