diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
index 021e228..73bf3af 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\Language\Language;
 
+use Drupal\Core\Language\Language;
+
 /**
  * Test case to verify node_access functionality for multiple languages.
  */
@@ -24,7 +26,7 @@ class NodeAccessLanguageTest extends NodeTestBase {
   public static function getInfo() {
     return array(
       'name' => 'Node access language',
-      'description' => 'Test node_access functionality with multiple languages.',
+      'description' => 'Test node_access and db_select with node_access tag functionality with multiple languages.',
       'group' => 'Node',
     );
   }
@@ -42,16 +44,16 @@ function assertNodeAccess($ops, $node, $account, $langcode = NULL) {
   function setUp() {
     parent::setUp();
 
+    node_access_rebuild();
+
     // Clear permissions for authenticated users.
     db_delete('role_permission')
       ->condition('rid', DRUPAL_AUTHENTICATED_RID)
       ->execute();
-  }
 
-  /**
-   * Runs tests for node_access function with multiple languages.
-   */
-  function testNodeAccess() {
+    // Enable the private node feature of node_access_test module.
+    variable_set('node_access_test_private', TRUE);
+
     // Add Hungarian and Catalan.
     $language = new Language(array(
       'langcode' => 'hu',
@@ -61,31 +63,106 @@ function testNodeAccess() {
       'langcode' => 'ca',
     ));
     language_save($language);
+  }
 
-    // Tests the default access provided for a published Hungarian node.
+  /**
+   * Runs tests for node_access function with multiple languages.
+   */
+  function testNodeAccess() {
     $web_user = $this->drupalCreateUser(array('access content'));
-    $node = $this->drupalCreateNode(array('body' => array('hu' => array(array())), 'langcode' => 'hu'));
-    $this->assertTrue($node->langcode == 'hu', 'Node created as Hungarian.');
+    // Creating a public Node with langcode Hungarian, will be saved as
+    // the fallback in node access table.
+    $node_public = $this->drupalCreateNode(array('body' => array('hu' => array(array())), 'langcode' => 'hu', 'private' => FALSE));
+    $this->assertTrue($node_public->langcode == 'hu', t('Node created as Hungarian.'));
+
+    // Tests the default access provided for the public Hungarian node.
     $expected_node_access = array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE);
-    $this->assertNodeAccess($expected_node_access, $node, $web_user);
+    $expected_node_access_no_access = array('view' => FALSE, 'update' => FALSE, 'delete' => FALSE);
+    $this->assertNodeAccess($expected_node_access, $node_public, $web_user);
 
     // Tests that Hungarian provided specifically results in the same.
-    $this->assertNodeAccess($expected_node_access, $node, $web_user, 'hu');
+    $this->assertNodeAccess($expected_node_access, $node_public, $web_user, 'hu');
 
     // There is no specific Catalan version of this node and Croatian is not
-    // even set up on the system in this scenario, so these languages will not
-    // play a role in the node's permissions.
-    $this->assertNodeAccess($expected_node_access, $node, $web_user, 'ca');
-    $this->assertNodeAccess($expected_node_access, $node, $web_user, 'hr');
+    // even set up on the system in this scenario, so the user will not get
+    // access to these nodes.
+    $this->assertNodeAccess($expected_node_access_no_access, $node_public, $web_user, 'ca');
+    $this->assertNodeAccess($expected_node_access_no_access, $node_public, $web_user, 'hr');
 
     // Reset the node access cache and turn on our test node_access() code.
     drupal_static_reset('node_access');
     variable_set('node_access_test_secret_catalan', 1);
 
     // Tests that Hungarian is still accessible.
-    $this->assertNodeAccess($expected_node_access, $node, $web_user, 'hu');
+    $this->assertNodeAccess($expected_node_access, $node_public, $web_user, 'hu');
 
     // Tests that Catalan is not accessible anymore.
-    $this->assertNodeAccess(array('view' => FALSE, 'update' => FALSE, 'delete' => FALSE), $node, $web_user, 'ca');
+    $this->assertNodeAccess(array('view' => FALSE, 'update' => FALSE, 'delete' => FALSE), $node_public, $web_user, 'ca');
+
+  }
+
+  /**
+   * Runs tests for db_select with node_access tag and langcode.
+   */
+  function testNodeAccessQueryTag() {
+    $web_user = $this->drupalCreateUser(array('access content'));
+
+    // Creating a private Node with langcode Hungarian, will be saved as
+    // the fallback in node access table.
+    $node_private = $this->drupalCreateNode(array('body' => array('hu' => array(array())), 'langcode' => 'hu', 'private' => TRUE));
+    $this->assertTrue($node_private->langcode == 'hu', t('Node created as Hungarian.'));
+
+    // Creating a public Node with langcode Hungarian, will be saved as
+    // the fallback in node access table.
+    $node_public = $this->drupalCreateNode(array('body' => array('hu' => array(array())), 'langcode' => 'hu', 'private' => FALSE));
+    $this->assertTrue($node_public->langcode == 'hu', t('Node created as Hungarian.'));
+
+    // Query the nodes table as readonly user with Node Access Tag and no
+    // specific langcode.
+    $select = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->addMetaData('account', $web_user)
+    ->addTag('node_access');
+    $nids = $select->execute()->fetchAllAssoc('nid');
+
+    // Only the public node should be returned. Because no langcode is given it
+    // will use the fallback node (which is the hungarian node).
+    $this->assertEqual(count($nids), 1, t('db_select returns only 1 node'));
+    $this->assertTrue(array_key_exists($node_public->nid, $nids), t('Returned node id is public node'));
+
+    // Query the nodes table as readonly User with Node Access Tag and
+    // langcode de.
+    $select = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->addMetaData('account', $web_user)
+    ->addMetaData('langcode', 'de')
+    ->addTag('node_access');
+    $nids = $select->execute()->fetchAllAssoc('nid');
+
+    // Because both created nodes are in Hungarian, no Nodes are returned.
+    $this->assertTrue(empty($nids), t('db_select returns empty result'));
+
+    // Query the nodes table as User 1 (full access) with Node Access Tag and no
+    // specific langcode.
+    $select = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->addTag('node_access');
+    $nids = $select->execute()->fetchAllAssoc('nid');
+
+    // Both nodes are returned.
+    $this->assertEqual(count($nids), 2, t('db_select returns both nodes'));
+
+    // Query the nodes table as User 1 (full access) with Node Access Tag and
+    // langcode de.
+    $select = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->addMetaData('langcode', 'de')
+    ->addTag('node_access');
+    $nids = $select->execute()->fetchAllAssoc('nid');
+
+    // Both nodes are returned because node access tag is not invoked when
+    // the user is user 1.
+    $this->assertEqual(count($nids), 2, t('db_select returns both nodes'));
+
   }
 }
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 113cc3d..625bd31 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -233,10 +233,13 @@ function hook_node_grants($account, $op) {
  *   of this gid within this realm can edit this node.
  * - 'grant_delete': If set to 1 a user that has been identified as a member
  *   of this gid within this realm can delete this node.
+ * - 'langcode': Optional key. The language code of the grant version. This
+ *   value is set automatically from the $node parameter during database
+ *   storage.
  *
  *
- * When an implementation is interested in a node but want to deny access to
- * everyone, it may return a "deny all" grant:
+ * When an implementation is interested in a node in Catalan language, but want
+ * to deny access to everyone, it may return a "deny all" grant:
  *
  * @code
  * $grants[] = array(
@@ -246,6 +249,7 @@ function hook_node_grants($account, $op) {
  *   'grant_update' => 0,
  *   'grant_delete' => 0,
  *   'priority' => 1,
+ *   'langcode' => 'ca'
  * );
  * @endcode
  *
@@ -269,7 +273,7 @@ function hook_node_access_records(Drupal\node\Node $node) {
   // treated just like any other node and we completely ignore it.
   if ($node->private) {
     $grants = array();
-    // Only published nodes should be viewable to all users. If we allow access
+    // Only published Catalan nodes should be viewable to all users. If we allow access
     // blindly here, then all users could view an unpublished node.
     if ($node->status) {
       $grants[] = array(
@@ -278,6 +282,7 @@ function hook_node_access_records(Drupal\node\Node $node) {
         'grant_view' => 1,
         'grant_update' => 0,
         'grant_delete' => 0,
+        'langcode' => 'ca'
       );
     }
     // For the example_author array, the GID is equivalent to a UID, which
@@ -290,6 +295,7 @@ function hook_node_access_records(Drupal\node\Node $node) {
       'grant_view' => 1,
       'grant_update' => 1,
       'grant_delete' => 1,
+      'langcode' => 'ca'
     );
 
     return $grants;
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index 9e1ee1b..18c264d 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -149,6 +149,20 @@ function node_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'langcode' => array(
+        'description' => 'The {language}.langcode of this node.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'fallback' => array(
+        'description' => 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+      ),
       'gid' => array(
         'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
         'type' => 'int',
@@ -188,7 +202,7 @@ function node_schema() {
         'size' => 'tiny',
       ),
     ),
-    'primary key' => array('nid', 'gid', 'realm'),
+    'primary key' => array('nid', 'gid', 'realm', 'langcode'),
     'foreign keys' => array(
       'affected_node' => array(
         'table' => 'node',
@@ -729,6 +743,39 @@ function node_update_8010() {
 }
 
 /**
+ * Add language.langcode and fallback field to node_access table.
+ */
+function node_update_8011() {
+  // Add the langcode field.
+  $langcode_field = array(
+    'type' => 'varchar',
+    'length' => 12,
+    'not null' => TRUE,
+    'default' => '',
+    'description' => 'The {language}.langcode of this node.',
+  );
+  db_add_field('node_access', 'langcode', $langcode_field);
+
+  // Add the fallback field.
+  $fallback_field = array(
+    'description' => 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 1,
+  );
+  db_add_field('node_access', 'fallback', $fallback_field);
+
+  // Reset the primary key.
+  db_drop_primary_key('node_access');
+  db_add_primary_key('node_access', array('nid', 'gid', 'realm', 'langcode'));
+
+  // Rebuild node access. Since this may take considerable time,
+  // we flag this action for the site administrator.
+  node_access_rebuild();
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x"
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index fc53461..412a007 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2810,9 +2810,13 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
       $query = db_select('node_access');
       $query->addExpression('1');
       $query->condition('grant_' . $op, 1, '>=');
-      $nids = db_or()->condition('nid', $node->nid);
+      $nids = db_and()
+        ->condition('nid', $node->nid)
+        ->condition('langcode', $langcode);
       if ($node->status) {
-        $nids->condition('nid', 0);
+        $nids = db_or()
+                  ->condition($nids)
+                  ->condition('nid', 0);
       }
       $query->condition($nids);
       $query->range(0, 1);
@@ -3049,6 +3053,10 @@ function node_query_node_access_alter(AlterableInterface $query) {
   if (!$op = $query->getMetaData('op')) {
     $op = 'view';
   }
+  if (!$langcode = $query->getMetaData('langcode')) {
+    $language_content = language(LANGUAGE_TYPE_CONTENT);
+    $langcode = isset($language_content->langcode) ? $language_content->langcode : FALSE;
+  }
 
   // If $account can bypass node access, or there are no node access modules,
   // or the operation is 'view' and the $acount has a global view grant (i.e.,
@@ -3112,10 +3120,16 @@ function node_query_node_access_alter(AlterableInterface $query) {
         $subquery->condition($grant_conditions);
       }
       $subquery->condition('na.grant_' . $op, 1, '>=');
+      if ($langcode === FALSE) {
+        $subquery->condition('na.fallback', 1, '=');
+      }
+      else {
+        $subquery->condition('na.langcode', $langcode, '=');
+      }
+
       $field = 'nid';
       // Now handle entities.
       $subquery->where("$nalias.$field = na.nid");
-
       $query->exists($subquery);
     }
   }
@@ -3164,7 +3178,9 @@ function node_access_acquire_grants(Node $node, $delete = TRUE) {
  *   nid.
  * @param $grants
  *   A list of grants to write. Each grant is an array that must contain the
- *   following keys: realm, gid, grant_view, grant_update, grant_delete.
+ *   following keys: realm, gid, grant_view, grant_update, grant_delete and
+ *   langcode is an optional key which is set automatically from $node
+ *   parameter.
  *   The realm is specified by a particular module; the gid is as well, and
  *   is a module-defined id to define grant privileges. each grant_* field
  *   is a boolean value.
@@ -3187,7 +3203,7 @@ function _node_access_write_grants(Node $node, $grants, $realm = NULL, $delete =
 
   // Only perform work when node_access modules are active.
   if (!empty($grants) && count(module_implements('node_grants'))) {
-    $query = db_insert('node_access')->fields(array('nid', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete'));
+    $query = db_insert('node_access')->fields(array('nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete'));
     foreach ($grants as $grant) {
       if ($realm && $realm != $grant['realm']) {
         continue;
@@ -3195,6 +3211,16 @@ function _node_access_write_grants(Node $node, $grants, $realm = NULL, $delete =
       // Only write grants; denies are implicit.
       if ($grant['grant_view'] || $grant['grant_update'] || $grant['grant_delete']) {
         $grant['nid'] = $node->nid;
+        if (!isset($grant['langcode'])) {
+          $grant['langcode'] = $node->langcode;
+        }
+        // The record with the original langcode is used as fallback.
+        if (node_grant_is_fallback($node, $grant)) {
+          $grant['fallback'] = 1;
+        }
+        else {
+          $grant['fallback'] = 0;
+        }
         $query->values($grant);
       }
     }
@@ -3203,6 +3229,35 @@ function _node_access_write_grants(Node $node, $grants, $realm = NULL, $delete =
 }
 
 /**
+ * Determines if a translation should be the default for access.
+ *
+ * @param Drupal\node\Node $node
+ *   The $node being written to. All that is necessary is that it contains a
+ *   nid.
+ * @param array $grant
+ *   A single grant array taken from hook_node_access_records().
+ *
+ * @return Boolean
+ *   TRUE if this node is default for all languages.
+ */
+function node_grant_is_fallback(Node $node, $grant) {
+  // The node must be enabled for translation.
+  if (!translation_entity_enabled('node', $node->type)) {
+    return TRUE;
+  }
+  elseif ($node->langcode == LANGUAGE_NOT_APPLICABLE) {
+    return TRUE;
+  }
+  elseif ($node->langcode == LANGUAGE_NOT_SPECIFIED) {
+    return TRUE;
+  }
+  elseif ($node->langcode == LANGUAGE_MULTIPLE) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
  * Toggles or reads the value of a flag for rebuilding the node access grants.
  *
  * When the flag is set, a message is displayed to users with 'access
