diff --git a/homeassistant/components/group/button.py b/homeassistant/components/group/button.py
new file mode 100644
index 0000000000000000000000000000000000000000..d848168661521cc5182008eb169a19f1f719a099
--- /dev/null
+++ b/homeassistant/components/group/button.py
@@ -0,0 +1,131 @@
+"""Platform allowing several button entities to be grouped into one single button."""
+
+from __future__ import annotations
+
+from typing import Any
+
+import voluptuous as vol
+
+from homeassistant.components.button import (
+    DOMAIN,
+    PLATFORM_SCHEMA as BUTTON_PLATFORM_SCHEMA,
+    SERVICE_PRESS,
+    ButtonEntity,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.const import (
+    ATTR_ENTITY_ID,
+    CONF_ENTITIES,
+    CONF_NAME,
+    CONF_UNIQUE_ID,
+    STATE_UNAVAILABLE,
+)
+from homeassistant.core import HomeAssistant, callback
+from homeassistant.helpers import config_validation as cv, entity_registry as er
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
+
+from .entity import GroupEntity
+
+DEFAULT_NAME = "Button group"
+
+# No limit on parallel updates to enable a group calling another group
+PARALLEL_UPDATES = 0
+
+PLATFORM_SCHEMA = BUTTON_PLATFORM_SCHEMA.extend(
+    {
+        vol.Required(CONF_ENTITIES): cv.entities_domain(DOMAIN),
+        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
+        vol.Optional(CONF_UNIQUE_ID): cv.string,
+    }
+)
+
+
+async def async_setup_platform(
+    _: HomeAssistant,
+    config: ConfigType,
+    async_add_entities: AddEntitiesCallback,
+    __: DiscoveryInfoType | None = None,
+) -> None:
+    """Set up the button group platform."""
+    async_add_entities(
+        [
+            ButtonGroup(
+                config.get(CONF_UNIQUE_ID),
+                config[CONF_NAME],
+                config[CONF_ENTITIES],
+            )
+        ]
+    )
+
+
+async def async_setup_entry(
+    hass: HomeAssistant,
+    config_entry: ConfigEntry,
+    async_add_entities: AddEntitiesCallback,
+) -> None:
+    """Initialize button group config entry."""
+    registry = er.async_get(hass)
+    entities = er.async_validate_entity_ids(
+        registry, config_entry.options[CONF_ENTITIES]
+    )
+    async_add_entities(
+        [
+            ButtonGroup(
+                config_entry.entry_id,
+                config_entry.title,
+                entities,
+            )
+        ]
+    )
+
+
+@callback
+def async_create_preview_button(
+    hass: HomeAssistant, name: str, validated_config: dict[str, Any]
+) -> ButtonGroup:
+    """Create a preview button."""
+    return ButtonGroup(
+        None,
+        name,
+        validated_config[CONF_ENTITIES],
+    )
+
+
+class ButtonGroup(GroupEntity, ButtonEntity):
+    """Representation of an button group."""
+
+    _attr_available = False
+    _attr_should_poll = False
+
+    def __init__(
+        self,
+        unique_id: str | None,
+        name: str,
+        entity_ids: list[str],
+    ) -> None:
+        """Initialize a button group."""
+        self._entity_ids = entity_ids
+        self._attr_name = name
+        self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids}
+        self._attr_unique_id = unique_id
+
+    async def async_press(self) -> None:
+        """Forward the press to all buttons in the group."""
+        await self.hass.services.async_call(
+            DOMAIN,
+            SERVICE_PRESS,
+            {ATTR_ENTITY_ID: self._entity_ids},
+            blocking=True,
+            context=self._context,
+        )
+
+    @callback
+    def async_update_group_state(self) -> None:
+        """Query all members and determine the button group state."""
+        # Set group as unavailable if all members are unavailable or missing
+        self._attr_available = any(
+            state.state != STATE_UNAVAILABLE
+            for entity_id in self._entity_ids
+            if (state := self.hass.states.get(entity_id)) is not None
+        )
diff --git a/homeassistant/components/group/config_flow.py b/homeassistant/components/group/config_flow.py
index 4eb0f1cdd52c06bdafb19dd8254a18c032c37745..54ef7d0626f68afd6012fc172f0b316c264c4642 100644
--- a/homeassistant/components/group/config_flow.py
+++ b/homeassistant/components/group/config_flow.py
@@ -23,6 +23,7 @@ from homeassistant.helpers.schema_config_entry_flow import (
 )
 
 from .binary_sensor import CONF_ALL, async_create_preview_binary_sensor
+from .button import async_create_preview_button
 from .const import CONF_HIDE_MEMBERS, CONF_IGNORE_NON_NUMERIC, DOMAIN
 from .cover import async_create_preview_cover
 from .entity import GroupEntity
@@ -146,6 +147,7 @@ async def light_switch_options_schema(
 
 GROUP_TYPES = [
     "binary_sensor",
+    "button",
     "cover",
     "event",
     "fan",
@@ -185,6 +187,11 @@ CONFIG_FLOW = {
         preview="group",
         validate_user_input=set_group_type("binary_sensor"),
     ),
+    "button": SchemaFlowFormStep(
+        basic_group_config_schema("button"),
+        preview="group",
+        validate_user_input=set_group_type("button"),
+    ),
     "cover": SchemaFlowFormStep(
         basic_group_config_schema("cover"),
         preview="group",
@@ -234,6 +241,10 @@ OPTIONS_FLOW = {
         binary_sensor_options_schema,
         preview="group",
     ),
+    "button": SchemaFlowFormStep(
+        partial(basic_group_options_schema, "button"),
+        preview="group",
+    ),
     "cover": SchemaFlowFormStep(
         partial(basic_group_options_schema, "cover"),
         preview="group",
@@ -275,6 +286,7 @@ CREATE_PREVIEW_ENTITY: dict[
     Callable[[HomeAssistant, str, dict[str, Any]], GroupEntity | MediaPlayerGroup],
 ] = {
     "binary_sensor": async_create_preview_binary_sensor,
+    "button": async_create_preview_button,
     "cover": async_create_preview_cover,
     "event": async_create_preview_event,
     "fan": async_create_preview_fan,
diff --git a/homeassistant/components/group/strings.json b/homeassistant/components/group/strings.json
index bff1f1e22ec6f447b639057039e96d3b2d0716fe..dc850804d9476e07ad77ac12e354a993bee8a59e 100644
--- a/homeassistant/components/group/strings.json
+++ b/homeassistant/components/group/strings.json
@@ -7,6 +7,7 @@
         "description": "Groups allow you to create a new entity that represents multiple entities of the same type.",
         "menu_options": {
           "binary_sensor": "Binary sensor group",
+          "button": "Button group",
           "cover": "Cover group",
           "event": "Event group",
           "fan": "Fan group",
@@ -27,6 +28,14 @@
           "name": "[%key:common::config_flow::data::name%]"
         }
       },
+      "button": {
+        "title": "[%key:component::group::config::step::user::title%]",
+        "data": {
+          "entities": "[%key:component::group::config::step::binary_sensor::data::entities%]",
+          "hide_members": "[%key:component::group::config::step::binary_sensor::data::hide_members%]",
+          "name": "[%key:common::config_flow::data::name%]"
+        }
+      },
       "cover": {
         "title": "[%key:component::group::config::step::user::title%]",
         "data": {
@@ -109,6 +118,12 @@
           "hide_members": "[%key:component::group::config::step::binary_sensor::data::hide_members%]"
         }
       },
+      "button": {
+        "data": {
+          "entities": "[%key:component::group::config::step::binary_sensor::data::entities%]",
+          "hide_members": "[%key:component::group::config::step::binary_sensor::data::hide_members%]"
+        }
+      },
       "cover": {
         "data": {
           "entities": "[%key:component::group::config::step::binary_sensor::data::entities%]",
diff --git a/tests/components/group/test_button.py b/tests/components/group/test_button.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3f4a720d53de043e73a67e67e0803b0a9c96d01
--- /dev/null
+++ b/tests/components/group/test_button.py
@@ -0,0 +1,122 @@
+"""The tests for the group button platform."""
+
+from freezegun.api import FrozenDateTimeFactory
+import pytest
+
+from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
+from homeassistant.components.group import DOMAIN
+from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, STATE_UNKNOWN
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers import entity_registry as er
+from homeassistant.setup import async_setup_component
+from homeassistant.util import dt as dt_util
+
+
+async def test_default_state(
+    hass: HomeAssistant, entity_registry: er.EntityRegistry
+) -> None:
+    """Test button group default state."""
+    hass.states.async_set("button.notify_light", "2021-01-01T23:59:59.123+00:00")
+    await async_setup_component(
+        hass,
+        BUTTON_DOMAIN,
+        {
+            BUTTON_DOMAIN: {
+                "platform": DOMAIN,
+                "entities": ["button.notify_light", "button.self_destruct"],
+                "name": "Button group",
+                "unique_id": "unique_identifier",
+            }
+        },
+    )
+    await hass.async_block_till_done()
+    await hass.async_start()
+    await hass.async_block_till_done()
+
+    state = hass.states.get("button.button_group")
+    assert state is not None
+    assert state.state == STATE_UNKNOWN
+    assert state.attributes.get(ATTR_ENTITY_ID) == [
+        "button.notify_light",
+        "button.self_destruct",
+    ]
+
+    entry = entity_registry.async_get("button.button_group")
+    assert entry
+    assert entry.unique_id == "unique_identifier"
+
+
+async def test_state_reporting(hass: HomeAssistant) -> None:
+    """Test the state reporting.
+
+    The group state is unavailable if all group members are unavailable.
+    Otherwise, the group state represents the last time the grouped button was pressed.
+    """
+    await async_setup_component(
+        hass,
+        BUTTON_DOMAIN,
+        {
+            BUTTON_DOMAIN: {
+                "platform": DOMAIN,
+                "entities": ["button.test1", "button.test2"],
+            }
+        },
+    )
+    await hass.async_block_till_done()
+    await hass.async_start()
+    await hass.async_block_till_done()
+
+    # Initial state with no group member in the state machine -> unavailable
+    assert hass.states.get("button.button_group").state == STATE_UNAVAILABLE
+
+    # All group members unavailable -> unavailable
+    hass.states.async_set("button.test1", STATE_UNAVAILABLE)
+    hass.states.async_set("button.test2", STATE_UNAVAILABLE)
+    await hass.async_block_till_done()
+    assert hass.states.get("button.button_group").state == STATE_UNAVAILABLE
+
+    # All group members available, but no group member pressed -> unknown
+    hass.states.async_set("button.test1", "2021-01-01T23:59:59.123+00:00")
+    hass.states.async_set("button.test2", "2022-02-02T23:59:59.123+00:00")
+    await hass.async_block_till_done()
+    assert hass.states.get("button.button_group").state == STATE_UNKNOWN
+
+
+@pytest.mark.usefixtures("enable_custom_integrations")
+async def test_service_calls(
+    hass: HomeAssistant, freezer: FrozenDateTimeFactory
+) -> None:
+    """Test service calls."""
+    await async_setup_component(
+        hass,
+        BUTTON_DOMAIN,
+        {
+            BUTTON_DOMAIN: [
+                {"platform": "demo"},
+                {
+                    "platform": DOMAIN,
+                    "entities": [
+                        "button.push",
+                        "button.self_destruct",
+                    ],
+                },
+            ]
+        },
+    )
+    await hass.async_block_till_done()
+
+    assert hass.states.get("button.button_group").state == STATE_UNKNOWN
+    assert hass.states.get("button.push").state == STATE_UNKNOWN
+
+    now = dt_util.parse_datetime("2021-01-09 12:00:00+00:00")
+    freezer.move_to(now)
+
+    await hass.services.async_call(
+        BUTTON_DOMAIN,
+        SERVICE_PRESS,
+        {ATTR_ENTITY_ID: "button.button_group"},
+        blocking=True,
+    )
+
+    assert hass.states.get("button.button_group").state == now.isoformat()
+    assert hass.states.get("button.push").state == now.isoformat()
diff --git a/tests/components/group/test_config_flow.py b/tests/components/group/test_config_flow.py
index c6ee4ae5a87d40609b169c8c38f9d09870b0439f..dc40b647e2e4b88e52be1f585d0bb9241aab5cbf 100644
--- a/tests/components/group/test_config_flow.py
+++ b/tests/components/group/test_config_flow.py
@@ -29,6 +29,7 @@ from tests.typing import WebSocketGenerator
     [
         ("binary_sensor", "on", "on", {}, {}, {"all": False}, {}),
         ("binary_sensor", "on", "on", {}, {"all": True}, {"all": True}, {}),
+        ("button", STATE_UNKNOWN, "2021-01-01T23:59:59.123+00:00", {}, {}, {}, {}),
         ("cover", "open", "open", {}, {}, {}, {}),
         (
             "event",
@@ -135,6 +136,7 @@ async def test_config_flow(
     ("group_type", "extra_input"),
     [
         ("binary_sensor", {"all": False}),
+        ("button", {}),
         ("cover", {}),
         ("event", {}),
         ("fan", {}),
@@ -212,6 +214,7 @@ def get_suggested(schema, key):
     ("group_type", "member_state", "extra_options", "options_options"),
     [
         ("binary_sensor", "on", {"all": False}, {}),
+        ("button", "2021-01-01T23:59:59.123+00:00", {}, {}),
         ("cover", "open", {}, {}),
         ("event", "2021-01-01T23:59:59.123+00:00", {}, {}),
         ("fan", "on", {}, {}),
@@ -396,6 +399,7 @@ async def test_all_options(
     ("group_type", "extra_input"),
     [
         ("binary_sensor", {"all": False}),
+        ("button", {}),
         ("cover", {}),
         ("event", {}),
         ("fan", {}),
@@ -491,6 +495,7 @@ SENSOR_ATTRS = [{"icon": "mdi:calculator"}, {"max_entity_id": "sensor.input_two"
     ("domain", "extra_user_input", "input_states", "group_state", "extra_attributes"),
     [
         ("binary_sensor", {"all": True}, ["on", "off"], "off", [{}, {}]),
+        ("button", {}, ["", ""], "unknown", [{}, {}]),
         ("cover", {}, ["open", "closed"], "open", COVER_ATTRS),
         ("event", {}, ["", ""], "unknown", EVENT_ATTRS),
         ("fan", {}, ["on", "off"], "on", FAN_ATTRS),
@@ -600,6 +605,7 @@ async def test_config_flow_preview(
     ),
     [
         ("binary_sensor", {"all": True}, {"all": False}, ["on", "off"], "on", [{}, {}]),
+        ("button", {}, {}, ["", ""], "unknown", [{}, {}]),
         ("cover", {}, {}, ["open", "closed"], "open", COVER_ATTRS),
         ("event", {}, {}, ["", ""], "unknown", EVENT_ATTRS),
         ("fan", {}, {}, ["on", "off"], "on", FAN_ATTRS),