diff --git a/esphome/components/thermostat/climate.py b/esphome/components/thermostat/climate.py
index 5e26e6d6de..8aa61dbb93 100644
--- a/esphome/components/thermostat/climate.py
+++ b/esphome/components/thermostat/climate.py
@@ -69,6 +69,8 @@ from esphome.const import (
 )
 
 CONF_PRESET_CHANGE = "preset_change"
+CONF_DEFAULT_PRESET = "default_preset"
+CONF_ON_BOOT_RESTORE_FROM = "on_boot_restore_from"
 
 CODEOWNERS = ["@kbx81"]
 
@@ -80,6 +82,13 @@ ThermostatClimate = thermostat_ns.class_(
 ThermostatClimateTargetTempConfig = thermostat_ns.struct(
     "ThermostatClimateTargetTempConfig"
 )
+OnBootRestoreFrom = thermostat_ns.enum("OnBootRestoreFrom")
+ON_BOOT_RESTORE_FROM = {
+    "MEMORY": OnBootRestoreFrom.MEMORY,
+    "DEFAULT_PRESET": OnBootRestoreFrom.DEFAULT_PRESET,
+}
+validate_on_boot_restore_from = cv.enum(ON_BOOT_RESTORE_FROM, upper=True)
+
 ClimateMode = climate_ns.enum("ClimateMode")
 CLIMATE_MODES = {
     "OFF": ClimateMode.CLIMATE_MODE_OFF,
@@ -125,6 +134,17 @@ def validate_temperature_preset(preset, root_config, name, requirements):
                 )
 
 
+def generate_comparable_preset(config, name):
+    comparable_preset = f"{CONF_PRESET}:\n" f"  -  {CONF_NAME}: {name}\n"
+
+    if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config:
+        comparable_preset += f"     {CONF_DEFAULT_TARGET_TEMPERATURE_LOW}: {config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]}\n"
+    if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config:
+        comparable_preset += f"     {CONF_DEFAULT_TARGET_TEMPERATURE_HIGH}: {config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]}\n"
+
+    return comparable_preset
+
+
 def validate_thermostat(config):
     # verify corresponding action(s) exist(s) for any defined climate mode or action
     requirements = {
@@ -277,13 +297,32 @@ def validate_thermostat(config):
             CONF_DEFAULT_TARGET_TEMPERATURE_LOW: [CONF_HEAT_ACTION],
         }
 
-    # Validate temperature requirements for default configuraation
-    validate_temperature_preset(config, config, "default", requirements)
+    # Legacy high/low configs
+    if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config:
+        comparable_preset = generate_comparable_preset(config, "Your new preset")
 
-    # Validate temperature requirements for away configuration
+        raise cv.Invalid(
+            f"{CONF_DEFAULT_TARGET_TEMPERATURE_LOW} is no longer valid. Please switch to using a preset for an equivalent experience.\nEquivalent configuration:\n\n"
+            f"{comparable_preset}"
+        )
+    if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config:
+        comparable_preset = generate_comparable_preset(config, "Your new preset")
+
+        raise cv.Invalid(
+            f"{CONF_DEFAULT_TARGET_TEMPERATURE_HIGH} is no longer valid. Please switch to using a preset for an equivalent experience.\nEquivalent configuration:\n\n"
+            f"{comparable_preset}"
+        )
+
+    # Legacy away mode - raise an error instructing the user to switch to presets
     if CONF_AWAY_CONFIG in config:
-        away = config[CONF_AWAY_CONFIG]
-        validate_temperature_preset(away, config, "away", requirements)
+        comparable_preset = generate_comparable_preset(config[CONF_AWAY_CONFIG], "Away")
+
+        raise cv.Invalid(
+            f"{CONF_AWAY_CONFIG} is no longer valid. Please switch to using a preset named "
+            "Away"
+            " for an equivalent experience.\nEquivalent configuration:\n\n"
+            f"{comparable_preset}"
+        )
 
     # Validate temperature requirements for presets
     if CONF_PRESET in config:
@@ -292,7 +331,12 @@ def validate_thermostat(config):
                 preset_config, config, preset_config[CONF_NAME], requirements
             )
 
-    # Verify default climate mode is valid given above configuration
+    # Warn about using the removed CONF_DEFAULT_MODE and advise users
+    if CONF_DEFAULT_MODE in config and config[CONF_DEFAULT_MODE] is not None:
+        raise cv.Invalid(
+            f"{CONF_DEFAULT_MODE} is no longer valid. Please switch to using presets and specify a {CONF_DEFAULT_PRESET}."
+        )
+
     default_mode = config[CONF_DEFAULT_MODE]
     requirements = {
         "HEAT_COOL": [CONF_COOL_ACTION, CONF_HEAT_ACTION],
@@ -403,6 +447,38 @@ def validate_thermostat(config):
                         f"{CONF_SWING_MODE} is set to {swing_mode} for {preset_config[CONF_NAME]} but {req} is not present in the configuration"
                     )
 
+    # If a default preset is requested then ensure that preset is defined
+    if CONF_DEFAULT_PRESET in config:
+        default_preset = config[CONF_DEFAULT_PRESET]
+
+        if CONF_PRESET not in config:
+            raise cv.Invalid(
+                f"{CONF_DEFAULT_PRESET} is specified but no presets are defined"
+            )
+
+        presets = config[CONF_PRESET]
+        found_preset = False
+
+        for preset in presets:
+            if preset[CONF_NAME] == default_preset:
+                found_preset = True
+                break
+
+        if found_preset is False:
+            raise cv.Invalid(
+                f"{CONF_DEFAULT_PRESET} set to '{default_preset}' but no such preset has been defined. Available presets: {[preset[CONF_NAME] for preset in presets]}"
+            )
+
+    # If restoring default preset on boot is true then ensure we have a default preset
+    if (
+        CONF_ON_BOOT_RESTORE_FROM in config
+        and config[CONF_ON_BOOT_RESTORE_FROM] is OnBootRestoreFrom.DEFAULT_PRESET
+    ):
+        if CONF_DEFAULT_PRESET not in config:
+            raise cv.Invalid(
+                f"{CONF_DEFAULT_PRESET} must be defined to use {CONF_ON_BOOT_RESTORE_FROM} in DEFAULT_PRESET mode"
+            )
+
     if config[CONF_FAN_WITH_COOLING] is True and CONF_FAN_ONLY_ACTION not in config:
         raise cv.Invalid(
             f"{CONF_FAN_ONLY_ACTION} must be defined to use {CONF_FAN_WITH_COOLING}"
@@ -502,9 +578,8 @@ CONFIG_SCHEMA = cv.All(
             cv.Optional(
                 CONF_TARGET_TEMPERATURE_CHANGE_ACTION
             ): automation.validate_automation(single=True),
-            cv.Optional(CONF_DEFAULT_MODE, default="OFF"): cv.templatable(
-                validate_climate_mode
-            ),
+            cv.Optional(CONF_DEFAULT_MODE, default=None): cv.valid,
+            cv.Optional(CONF_DEFAULT_PRESET): cv.templatable(cv.string),
             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
             cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
             cv.Optional(
@@ -542,6 +617,7 @@ CONFIG_SCHEMA = cv.All(
                 }
             ),
             cv.Optional(CONF_PRESET): cv.ensure_list(PRESET_CONFIG_SCHEMA),
+            cv.Optional(CONF_ON_BOOT_RESTORE_FROM): validate_on_boot_restore_from,
             cv.Optional(CONF_PRESET_CHANGE): automation.validate_automation(
                 single=True
             ),
@@ -564,9 +640,10 @@ async def to_code(config):
         CONF_COOL_ACTION in config
         or (config[CONF_FAN_ONLY_COOLING] and CONF_FAN_ONLY_ACTION in config)
     )
+    if two_points_available:
+        cg.add(var.set_supports_two_points(True))
 
     sens = await cg.get_variable(config[CONF_SENSOR])
-    cg.add(var.set_default_mode(config[CONF_DEFAULT_MODE]))
     cg.add(
         var.set_set_point_minimum_differential(
             config[CONF_SET_POINT_MINIMUM_DIFFERENTIAL]
@@ -579,23 +656,6 @@ async def to_code(config):
     cg.add(var.set_heat_deadband(config[CONF_HEAT_DEADBAND]))
     cg.add(var.set_heat_overrun(config[CONF_HEAT_OVERRUN]))
 
-    if two_points_available is True:
-        cg.add(var.set_supports_two_points(True))
-        normal_config = ThermostatClimateTargetTempConfig(
-            config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
-            config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH],
-        )
-    elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config:
-        cg.add(var.set_supports_two_points(False))
-        normal_config = ThermostatClimateTargetTempConfig(
-            config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
-        )
-    elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config:
-        cg.add(var.set_supports_two_points(False))
-        normal_config = ThermostatClimateTargetTempConfig(
-            config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]
-        )
-
     if CONF_MAX_COOLING_RUN_TIME in config:
         cg.add(
             var.set_cooling_maximum_run_time_in_sec(config[CONF_MAX_COOLING_RUN_TIME])
@@ -661,7 +721,6 @@ async def to_code(config):
     cg.add(var.set_supports_fan_with_heating(config[CONF_FAN_WITH_HEATING]))
 
     cg.add(var.set_use_startup_delay(config[CONF_STARTUP_DELAY]))
-    cg.add(var.set_preset_config(ClimatePreset.CLIMATE_PRESET_HOME, normal_config))
 
     await automation.build_automation(
         var.get_idle_action_trigger(), [], config[CONF_IDLE_ACTION]
@@ -808,27 +867,8 @@ async def to_code(config):
             config[CONF_TARGET_TEMPERATURE_CHANGE_ACTION],
         )
 
-    if CONF_AWAY_CONFIG in config:
-        away = config[CONF_AWAY_CONFIG]
-
-        if two_points_available is True:
-            away_config = ThermostatClimateTargetTempConfig(
-                away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
-                away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH],
-            )
-        elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in away:
-            away_config = ThermostatClimateTargetTempConfig(
-                away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
-            )
-        elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in away:
-            away_config = ThermostatClimateTargetTempConfig(
-                away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]
-            )
-        cg.add(var.set_preset_config(ClimatePreset.CLIMATE_PRESET_AWAY, away_config))
-
     if CONF_PRESET in config:
         for preset_config in config[CONF_PRESET]:
-
             name = preset_config[CONF_NAME]
             standard_preset = None
             if name.upper() in climate.CLIMATE_PRESETS:
@@ -872,6 +912,19 @@ async def to_code(config):
             else:
                 cg.add(var.set_custom_preset_config(name, preset_target_variable))
 
+    if CONF_DEFAULT_PRESET in config:
+        default_preset_name = config[CONF_DEFAULT_PRESET]
+
+        # if the name is a built in preset use the appropriate naming format
+        if default_preset_name.upper() in climate.CLIMATE_PRESETS:
+            climate_preset = climate.CLIMATE_PRESETS[default_preset_name.upper()]
+            cg.add(var.set_default_preset(climate_preset))
+        else:
+            cg.add(var.set_default_preset(default_preset_name))
+
+    if CONF_ON_BOOT_RESTORE_FROM in config:
+        cg.add(var.set_on_boot_restore_from(config[CONF_ON_BOOT_RESTORE_FROM]))
+
     if CONF_PRESET_CHANGE in config:
         await automation.build_automation(
             var.get_preset_change_trigger(), [], config[CONF_PRESET_CHANGE]
diff --git a/esphome/components/thermostat/thermostat_climate.cpp b/esphome/components/thermostat/thermostat_climate.cpp
index dc4e1e437e..a9b03187d3 100644
--- a/esphome/components/thermostat/thermostat_climate.cpp
+++ b/esphome/components/thermostat/thermostat_climate.cpp
@@ -25,15 +25,27 @@ void ThermostatClimate::setup() {
     this->publish_state();
   });
   this->current_temperature = this->sensor_->state;
-  // restore all climate data, if possible
-  auto restore = this->restore_state_();
-  if (restore.has_value()) {
-    restore->to_call(this).perform();
-  } else {
-    // restore from defaults, change_away handles temps for us
-    this->mode = this->default_mode_;
-    this->change_preset_(climate::CLIMATE_PRESET_HOME);
+
+  auto use_default_preset = true;
+
+  if (this->on_boot_restore_from_ == thermostat::OnBootRestoreFrom::MEMORY) {
+    // restore all climate data, if possible
+    auto restore = this->restore_state_();
+    if (restore.has_value()) {
+      use_default_preset = false;
+      restore->to_call(this).perform();
+    }
   }
+
+  // Either we failed to restore state or the user has requested we always apply the default preset
+  if (use_default_preset) {
+    if (this->default_preset_ != climate::ClimatePreset::CLIMATE_PRESET_NONE) {
+      this->change_preset_(this->default_preset_);
+    } else if (!this->default_custom_preset_.empty()) {
+      this->change_custom_preset_(this->default_custom_preset_);
+    }
+  }
+
   // refresh the climate action based on the restored settings, we'll publish_state() later
   this->switch_to_action_(this->compute_action_(), false);
   this->switch_to_supplemental_action_(this->compute_supplemental_action_());
@@ -923,10 +935,12 @@ bool ThermostatClimate::supplemental_heating_required_() {
           (this->supplemental_action_ == climate::CLIMATE_ACTION_HEATING));
 }
 
-void ThermostatClimate::dump_preset_config_(const std::string &preset,
-                                            const ThermostatClimateTargetTempConfig &config) {
+void ThermostatClimate::dump_preset_config_(const std::string &preset, const ThermostatClimateTargetTempConfig &config,
+                                            bool is_default_preset) {
   const auto *preset_name = preset.c_str();
 
+  ESP_LOGCONFIG(TAG, "      %s Is Default: %s", preset_name, YESNO(is_default_preset));
+
   if (this->supports_heat_) {
     if (this->supports_two_points_) {
       ESP_LOGCONFIG(TAG, "      %s Default Target Temperature Low: %.1f°C", preset_name,
@@ -1061,7 +1075,15 @@ ThermostatClimate::ThermostatClimate()
       temperature_change_trigger_(new Trigger<>()),
       preset_change_trigger_(new Trigger<>()) {}
 
-void ThermostatClimate::set_default_mode(climate::ClimateMode default_mode) { this->default_mode_ = default_mode; }
+void ThermostatClimate::set_default_preset(const std::string &custom_preset) {
+  this->default_custom_preset_ = custom_preset;
+}
+
+void ThermostatClimate::set_default_preset(climate::ClimatePreset preset) { this->default_preset_ = preset; }
+
+void ThermostatClimate::set_on_boot_restore_from(thermostat::OnBootRestoreFrom on_boot_restore_from) {
+  this->on_boot_restore_from_ = on_boot_restore_from;
+}
 void ThermostatClimate::set_set_point_minimum_differential(float differential) {
   this->set_point_minimum_differential_ = differential;
 }
@@ -1213,8 +1235,9 @@ Trigger<> *ThermostatClimate::get_preset_change_trigger() const { return this->p
 void ThermostatClimate::dump_config() {
   LOG_CLIMATE("", "Thermostat", this);
 
-  if (this->supports_two_points_)
+  if (this->supports_two_points_) {
     ESP_LOGCONFIG(TAG, "  Minimum Set Point Differential: %.1f°C", this->set_point_minimum_differential_);
+  }
   ESP_LOGCONFIG(TAG, "  Start-up Delay Enabled: %s", YESNO(this->use_startup_delay_));
   if (this->supports_cool_) {
     ESP_LOGCONFIG(TAG, "  Cooling Parameters:");
@@ -1284,7 +1307,7 @@ void ThermostatClimate::dump_config() {
     const auto *preset_name = LOG_STR_ARG(climate::climate_preset_to_string(it.first));
 
     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true));
-    this->dump_preset_config_(preset_name, it.second);
+    this->dump_preset_config_(preset_name, it.second, it.first == this->default_preset_);
   }
 
   ESP_LOGCONFIG(TAG, "  Supported CUSTOM PRESETS: ");
@@ -1292,8 +1315,10 @@ void ThermostatClimate::dump_config() {
     const auto *preset_name = it.first.c_str();
 
     ESP_LOGCONFIG(TAG, "    Supports %s: %s", preset_name, YESNO(true));
-    this->dump_preset_config_(preset_name, it.second);
+    this->dump_preset_config_(preset_name, it.second, it.first == this->default_custom_preset_);
   }
+  ESP_LOGCONFIG(TAG, "  On boot, restore from: %s",
+                this->on_boot_restore_from_ == thermostat::DEFAULT_PRESET ? "DEFAULT_PRESET" : "MEMORY");
 }
 
 ThermostatClimateTargetTempConfig::ThermostatClimateTargetTempConfig() = default;
diff --git a/esphome/components/thermostat/thermostat_climate.h b/esphome/components/thermostat/thermostat_climate.h
index a5498dc53d..aa7529cfb1 100644
--- a/esphome/components/thermostat/thermostat_climate.h
+++ b/esphome/components/thermostat/thermostat_climate.h
@@ -22,6 +22,7 @@ enum ThermostatClimateTimerIndex : size_t {
   TIMER_IDLE_ON = 9,
 };
 
+enum OnBootRestoreFrom : size_t { MEMORY = 0, DEFAULT_PRESET = 1 };
 struct ThermostatClimateTimer {
   const std::string name;
   bool active;
@@ -57,7 +58,9 @@ class ThermostatClimate : public climate::Climate, public Component {
   void setup() override;
   void dump_config() override;
 
-  void set_default_mode(climate::ClimateMode default_mode);
+  void set_default_preset(const std::string &custom_preset);
+  void set_default_preset(climate::ClimatePreset preset);
+  void set_on_boot_restore_from(thermostat::OnBootRestoreFrom on_boot_restore_from);
   void set_set_point_minimum_differential(float differential);
   void set_cool_deadband(float deadband);
   void set_cool_overrun(float overrun);
@@ -225,7 +228,8 @@ class ThermostatClimate : public climate::Climate, public Component {
   bool supplemental_cooling_required_();
   bool supplemental_heating_required_();
 
-  void dump_preset_config_(const std::string &preset_name, const ThermostatClimateTargetTempConfig &config);
+  void dump_preset_config_(const std::string &preset_name, const ThermostatClimateTargetTempConfig &config,
+                           bool is_default_preset);
 
   /// The sensor used for getting the current temperature
   sensor::Sensor *sensor_{nullptr};
@@ -397,7 +401,6 @@ class ThermostatClimate : public climate::Climate, public Component {
   /// These are used to determine when a trigger/action needs to be called
   climate::ClimateAction supplemental_action_{climate::CLIMATE_ACTION_OFF};
   climate::ClimateFanMode prev_fan_mode_{climate::CLIMATE_FAN_ON};
-  climate::ClimateMode default_mode_{climate::CLIMATE_MODE_OFF};
   climate::ClimateMode prev_mode_{climate::CLIMATE_MODE_OFF};
   climate::ClimateSwingMode prev_swing_mode_{climate::CLIMATE_SWING_OFF};
 
@@ -441,6 +444,15 @@ class ThermostatClimate : public climate::Climate, public Component {
   std::map<climate::ClimatePreset, ThermostatClimateTargetTempConfig> preset_config_{};
   /// The set of custom preset configurations this thermostat supports (eg. "My Custom Preset")
   std::map<std::string, ThermostatClimateTargetTempConfig> custom_preset_config_{};
+
+  /// Default standard preset to use on start up
+  climate::ClimatePreset default_preset_{};
+  /// Default custom preset to use on start up
+  std::string default_custom_preset_{};
+
+  /// If set to DEFAULT_PRESET then the default preset is always used. When MEMORY prior
+  /// state will attempt to be restored if possible
+  thermostat::OnBootRestoreFrom on_boot_restore_from_{thermostat::OnBootRestoreFrom::MEMORY};
 };
 
 }  // namespace thermostat
diff --git a/tests/test3.yaml b/tests/test3.yaml
index 4eee0fd2c9..8fc66f4918 100644
--- a/tests/test3.yaml
+++ b/tests/test3.yaml
@@ -1061,8 +1061,13 @@ climate:
   - platform: thermostat
     name: Thermostat Climate
     sensor: ha_hello_world
-    default_target_temperature_low: 18°C
-    default_target_temperature_high: 24°C
+    preset:
+    - name: Default Preset
+      default_target_temperature_low: 18°C
+      default_target_temperature_high: 24°C
+    - name: Away
+      default_target_temperature_low: 16°C
+      default_target_temperature_high: 20°C
     idle_action:
       - switch.turn_on: gpio_switch1
     cool_action:
@@ -1137,9 +1142,6 @@ climate:
     fan_only_cooling: true
     fan_with_cooling: true
     fan_with_heating: true
-    away_config:
-      default_target_temperature_low: 16°C
-      default_target_temperature_high: 20°C
   - platform: pid
     id: pid_climate
     name: PID Climate Controller