diff --git a/core/modules/block_content/block_content.install b/core/modules/block_content/block_content.install
index 4279cde..8dd925f 100644
--- a/core/modules/block_content/block_content.install
+++ b/core/modules/block_content/block_content.install
@@ -5,7 +5,10 @@
  * Install, update and uninstall functions for the block_content module.
  */
 
+use Drupal\block_content\BlockContentStorageSchema;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Add 'revision_translation_affected' field to 'block_content' entities.
@@ -61,3 +64,70 @@ function block_content_update_8003() {
   \Drupal::entityDefinitionUpdateManager()
     ->installFieldStorageDefinition('revision_user', 'block_content', 'block_content', $revision_user);
 }
+
+/**
+ * @addtogroup updates-8.3.x
+ * @{
+ */
+
+/**
+ * Add and populate publishing status fields.
+ */
+function block_content_update_8300() {
+  $database = \Drupal::database();
+  $schema = $database->schema();
+  // Content Translation adds the content_translation_status field, to use this
+  // as an initial_from_field it can't be null and needs to be set to 1.
+  if ($schema->fieldExists('block_content_field_data', 'content_translation_status')) {
+    $database->update('block_content_field_data')
+      ->fields(['content_translation_status' => 1])
+      ->isNull('content_translation_status')
+      ->execute();
+  }
+  if ($schema->fieldExists('block_content_field_revision', 'content_translation_status')) {
+    $database->update('block_content_field_revision')
+      ->fields(['content_translation_status' => 1])
+      ->isNull('content_translation_status')
+      ->execute();
+  }
+
+  // Add the published entity key to the block_content entity type.
+  $manager = \Drupal::entityDefinitionUpdateManager();
+  $entity_type = $manager->getEntityType('block_content');
+  $entity_keys = $entity_type->getKeys();
+  $entity_keys['published'] = 'status';
+  $entity_type->set('entity_keys', $entity_keys);
+  $entity_type->setHandlerClass('storage_schema', BlockContentStorageSchema::class);
+  $manager->updateEntityType($entity_type);
+
+  // Install the publishing status field to the block_content entity type.
+  $status = BaseFieldDefinition::create('boolean')
+    ->setLabel(new TranslatableMarkup('Publishing status'))
+    ->setDescription(new TranslatableMarkup('A boolean indicating the published state.'))
+    ->setRevisionable(TRUE)
+    ->setTranslatable(TRUE)
+    ->setDefaultValue(TRUE);
+  $manager->installFieldStorageDefinition('status', 'block_content', 'block_content', $status);
+
+  // Empty the content_translation_status field before uninstalling.
+  if ($schema->fieldExists('block_content_field_data', 'content_translation_status')) {
+    $database->update('block_content_field_data')
+      ->fields(['content_translation_status' => NULL])
+      ->execute();
+  }
+  if ($schema->fieldExists('block_content_field_revision', 'content_translation_status')) {
+    $database->update('block_content_field_revision')
+      ->fields(['content_translation_status' => NULL])
+      ->execute();
+  }
+
+  // Uninstall the content_translation_status field if it existed.
+  $content_translation_status = $manager->getFieldStorageDefinition('content_translation_status', 'block_content');
+  if ($content_translation_status instanceof FieldStorageDefinitionInterface) {
+    $manager->uninstallFieldStorageDefinition($content_translation_status);
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.3.x".
+ */
diff --git a/core/modules/block_content/src/BlockContentAccessControlHandler.php b/core/modules/block_content/src/BlockContentAccessControlHandler.php
index d0c19c5..e3b555e 100644
--- a/core/modules/block_content/src/BlockContentAccessControlHandler.php
+++ b/core/modules/block_content/src/BlockContentAccessControlHandler.php
@@ -19,7 +19,7 @@ class BlockContentAccessControlHandler extends EntityAccessControlHandler {
    */
   protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
     if ($operation === 'view') {
-      return AccessResult::allowed();
+      return AccessResult::allowedIf($entity->isPublished());
     }
     return parent::checkAccess($entity, $operation, $account);
   }
diff --git a/core/modules/block_content/src/BlockContentInterface.php b/core/modules/block_content/src/BlockContentInterface.php
index 130cae1..75fdc59 100644
--- a/core/modules/block_content/src/BlockContentInterface.php
+++ b/core/modules/block_content/src/BlockContentInterface.php
@@ -4,12 +4,13 @@
 
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\RevisionLogInterface;
 
 /**
  * Provides an interface defining a custom block entity.
  */
-interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface {
+interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityPublishedInterface {
 
   /**
    * Returns the block revision log message.
diff --git a/core/modules/block_content/src/BlockContentStorageSchema.php b/core/modules/block_content/src/BlockContentStorageSchema.php
new file mode 100644
index 0000000..e1107fd
--- /dev/null
+++ b/core/modules/block_content/src/BlockContentStorageSchema.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\block_content;
+
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+
+class BlockContentStorageSchema extends SqlContentEntityStorageSchema  {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) {
+    $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
+
+    if ($storage_definition->getName() == 'status') {
+      if (\Drupal::database()->schema()->fieldExists('block_content_field_data', 'content_translation_status')) {
+        $schema['fields']['status']['initial_from_field'] = 'content_translation_status';
+      }
+      else {
+        // Set all block content as published.
+        $schema['fields']['status']['initial'] = 1;
+      }
+    }
+
+    return $schema;
+  }
+
+}
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 51ae6f6..3c7c6b6 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -19,6 +20,7 @@
  *   bundle_label = @Translation("Custom block type"),
  *   handlers = {
  *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
+ *     "storage_schema" = "Drupal\block_content\BlockContentStorageSchema",
  *     "access" = "Drupal\block_content\BlockContentAccessControlHandler",
  *     "list_builder" = "Drupal\block_content\BlockContentListBuilder",
  *     "view_builder" = "Drupal\block_content\BlockContentViewBuilder",
@@ -49,7 +51,8 @@
  *     "bundle" = "type",
  *     "label" = "info",
  *     "langcode" = "langcode",
- *     "uuid" = "uuid"
+ *     "uuid" = "uuid",
+ *     "published" = "status",
  *   },
  *   bundle_entity_type = "block_content_type",
  *   field_ui_base_route = "entity.block_content_type.edit_form",
@@ -64,6 +67,7 @@
 class BlockContent extends ContentEntityBase implements BlockContentInterface {
 
   use EntityChangedTrait;
+  use EntityPublishedTrait;
 
   /**
    * The theme the block is being created in.
@@ -154,6 +158,7 @@ public function delete() {
   public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
     $fields = parent::baseFieldDefinitions($entity_type);
+    $fields += static::publishedBaseFieldDefinitions($entity_type);
 
     $fields['id']->setLabel(t('Custom block ID'))
       ->setDescription(t('The custom block ID.'));
diff --git a/core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php b/core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php
new file mode 100644
index 0000000..8ac9da9
--- /dev/null
+++ b/core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\block_content\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests that block content settings are properly updated during database updates.
+ *
+ * @group block_content
+ */
+class BlockContentUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8-rc1.filled.standard.php.gz',
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.block-content-publishing-status-upgrade.php',
+    ];
+  }
+
+  /**
+   * Tests adding a status field to the block content entity type.
+   *
+   * @see block_content_update_8300()
+   */
+  public function testStatusField() {
+    // Check that the 'status' field does not exist prior to the update.
+    $field = \Drupal::entityDefinitionUpdateManager()->getFieldStorageDefinition('status', 'block_content');
+    $this->assertNull($field);
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that the field exists and has the correct label.
+    $updated_field = \Drupal::entityDefinitionUpdateManager()->getFieldStorageDefinition('status', 'block_content');
+    $this->assertEqual('Publishing status', $updated_field->getLabel());
+  }
+
+}
diff --git a/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php b/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php
new file mode 100644
index 0000000..9aa8091
--- /dev/null
+++ b/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\Tests\block_content\Functional;
+
+use Drupal\block_content\Entity\BlockContent;
+use Drupal\block_content\Entity\BlockContentType;
+use Drupal\simpletest\BlockCreationTrait;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests unpublishing of block_content entities.
+ *
+ * @group block_content
+ */
+class UnpublishedBlockTest extends BrowserTestBase {
+
+  use BlockCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'block_content'
+  ];
+
+  /**
+   * Tests unpublishing of block_content entities.
+   */
+  public function testViewShowsCorrectStates() {
+    $block_content = BlockContent::create(['type' => 'basic']);
+    $block_content->save();
+
+    $this->placeBlock('block_content:' . $block_content->uuid());
+
+    $this->drupalGet('<front>');
+    $page = $this->getSession()->getPage();
+    $this->assertTrue($page->has('css', '.block-block-content' . $block_content->uuid()));
+
+    $block_content->setPublished(FALSE);
+    $block_content->save();
+
+    $this->drupalGet('<front>');
+    $page = $this->getSession()->getPage();
+    $this->assertFalse($page->has('css', '.block-block-content' . $block_content->uuid()));
+  }
+}
diff --git a/core/modules/system/tests/fixtures/update/drupal-8.block-content-publishing-status-upgrade.php b/core/modules/system/tests/fixtures/update/drupal-8.block-content-publishing-status-upgrade.php
new file mode 100644
index 0000000..e2e01d5
--- /dev/null
+++ b/core/modules/system/tests/fixtures/update/drupal-8.block-content-publishing-status-upgrade.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Partial database to populate data for the Block Content update test.
+ */
+
+use Drupal\Core\Database\Database;
+
+$connection = Database::getConnection();
+
+$spec = [
+  'type' => 'int',
+  'not null' => FALSE,
+];
+$connection->schema()->addField('block_content_field_revision', 'content_translation_status', $spec);
+$connection->schema()->addField('block_content_field_data', 'content_translation_status', $spec);
