diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index d8fc3083c..a1d86d469 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -67,6 +67,7 @@ static t_config_enum_values s_keys_map_MachineLimitsUsage {
 CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(MachineLimitsUsage)
 
 static t_config_enum_values s_keys_map_PrintHostType {
+    { "prusalink",      htPrusaLink },
     { "octoprint",      htOctoPrint },
     { "duet",           htDuet },
     { "flashair",       htFlashAir },
@@ -1779,11 +1780,13 @@ void PrintConfigDef::init_fff_params()
     def->tooltip = L("Slic3r can upload G-code files to a printer host. This field must contain "
                    "the kind of the host.");
     def->enum_keys_map = &ConfigOptionEnum<PrintHostType>::get_enum_values();
+    def->enum_values.push_back("prusalink");
     def->enum_values.push_back("octoprint");
     def->enum_values.push_back("duet");
     def->enum_values.push_back("flashair");
     def->enum_values.push_back("astrobox");
     def->enum_values.push_back("repetier");
+    def->enum_labels.push_back("PrusaLink");
     def->enum_labels.push_back("OctoPrint");
     def->enum_labels.push_back("Duet");
     def->enum_labels.push_back("FlashAir");
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 890f8518e..efe71822b 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
 };
 
 enum PrintHostType {
-    htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
+    htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
 };
 
 enum AuthorizationType {
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 532e44e70..e194898ee 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -1141,6 +1141,10 @@ void Choice::set_value(const boost::any& value, bool change_event)
 	}
 	case coEnum: {
 		int val = boost::any_cast<int>(value);
+		if (m_opt_id.compare("host_type") == 0 && val != 0 && 
+			m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType
+			val--;
+
 		if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "fill_pattern")
 		{
 			std::string key;
@@ -1197,7 +1201,7 @@ void Choice::set_values(const wxArrayString &values)
 	auto ww = dynamic_cast<choice_ctrl*>(window);
 	auto value = ww->GetValue();
 	ww->Clear();
-	ww->Append("");
+//	ww->Append("");
 	for (const auto &el : values)
 		ww->Append(el);
 	ww->SetValue(value);
@@ -1219,7 +1223,10 @@ boost::any& Choice::get_value()
 
 	if (m_opt.type == coEnum)
 	{
-		if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "fill_pattern") {
+		if (m_opt_id.compare("host_type") == 0 && m_opt.enum_values.size() > field->GetCount()) {
+			// for case, when PrusaLink isn't used as a HostType
+			m_value = field->GetSelection()+1;
+		} else if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "fill_pattern") {
 			const std::string& key = m_opt.enum_values[field->GetSelection()];
 			m_value = int(ConfigOptionEnum<InfillPattern>::get_enum_values().at(key));
 		}
diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp
index bb0191b4d..7d20b15e5 100644
--- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp
+++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp
@@ -68,7 +68,8 @@ PresetForPrinter::PresetForPrinter(PhysicalPrinterDialog* parent, const std::str
             // update Print Host upload from the selected preset
             m_parent->get_printer()->update_from_preset(*preset);
             // update values in parent (PhysicalPrinterDialog)
-            m_parent->update();
+            m_parent->update(true);
+            
         }
 
         // update PrinterTechnology if it was changed
@@ -154,7 +155,8 @@ void PresetForPrinter::msw_rescale()
 
 PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_name) :
     DPIDialog(parent, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
-    m_printer("", wxGetApp().preset_bundle->physical_printers.default_config())
+    m_printer("", wxGetApp().preset_bundle->physical_printers.default_config()),
+    had_all_mk3(!printer_name.empty())
 {
     SetFont(wxGetApp().normal_font());
 #ifndef _WIN32
@@ -455,7 +457,7 @@ void PhysicalPrinterDialog::update_printhost_buttons()
     m_printhost_browse_btn->Enable(host->has_auto_discovery());
 }
 
-void PhysicalPrinterDialog::update()
+void PhysicalPrinterDialog::update(bool printer_change)
 {
     m_optgroup->reload_config();
 
@@ -463,13 +465,24 @@ void PhysicalPrinterDialog::update()
     // Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment)
     bool supports_multiple_printers = false;
     if (tech == ptFFF) {
-        m_optgroup->show_field("host_type");
-        m_optgroup->hide_field("printhost_authorization_type");
-        m_optgroup->show_field("printhost_apikey", true);
-        for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
-            m_optgroup->hide_field(opt_key);
+        update_host_type(printer_change);
         const auto opt = m_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
-        supports_multiple_printers = opt && opt->value == htRepetier;
+        m_optgroup->show_field("host_type");
+        if (opt->value == htPrusaLink)
+        {
+            m_optgroup->show_field("printhost_authorization_type");
+            AuthorizationType auth_type = m_config->option<ConfigOptionEnum<AuthorizationType>>("printhost_authorization_type")->value;
+            m_optgroup->show_field("printhost_apikey", auth_type == AuthorizationType::atKeyPassword);
+            for (const char* opt_key : { "printhost_user", "printhost_password" })
+                m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword);
+        } else {
+            m_optgroup->hide_field("printhost_authorization_type");
+            m_optgroup->show_field("printhost_apikey", true);
+            for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
+                m_optgroup->hide_field(opt_key);
+            supports_multiple_printers = opt && opt->value == htRepetier;
+        }
+        
     }
     else {
         m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false);
@@ -493,6 +506,57 @@ void PhysicalPrinterDialog::update()
     this->Layout();
 }
 
+void PhysicalPrinterDialog::update_host_type(bool printer_change)
+{
+    if (m_presets.empty())
+        return;
+    bool all_presets_are_from_mk3_family = true;
+
+    for (PresetForPrinter* prstft : m_presets) {
+        std::string preset_name = prstft->get_preset_name();
+        if (Preset* preset = wxGetApp().preset_bundle->printers.find_preset(preset_name)) {
+            std::string model_id = preset->config.opt_string("printer_model");
+            if (preset->vendor && preset->vendor->name == "Prusa Research") {
+                const std::vector<VendorProfile::PrinterModel>& models = preset->vendor->models;
+                auto it = std::find_if(models.begin(), models.end(),
+                    [model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; });
+                if (it != models.end() && it->family == "MK3")
+                    continue;
+            } else if (!preset->vendor && model_id.rfind("MK3", 0) == 0) {
+                continue;
+            }
+            
+        }
+        all_presets_are_from_mk3_family = false;
+        break;
+    }
+
+    Field* ht = m_optgroup->get_field("host_type");
+
+    wxArrayString types;
+    // Append localized enum_labels
+    assert(ht->m_opt.enum_labels.size() == ht->m_opt.enum_values.size());
+    for (size_t i = 0; i < ht->m_opt.enum_labels.size(); i++) {
+        if (ht->m_opt.enum_values[i] == "prusalink" && !all_presets_are_from_mk3_family)
+            continue;
+        types.Add(_(ht->m_opt.enum_labels[i]));
+    }
+
+    Choice* choice = dynamic_cast<Choice*>(ht);
+    choice->set_values(types);
+    auto set_to_choice_and_config = [this, choice](PrintHostType type) {
+        choice->set_value(static_cast<int>(type));
+        m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(type));
+    };
+    if ((printer_change && all_presets_are_from_mk3_family) || (!had_all_mk3 && all_presets_are_from_mk3_family))
+        set_to_choice_and_config(htPrusaLink);  
+    else if ((printer_change && !all_presets_are_from_mk3_family) || (!all_presets_are_from_mk3_family && m_config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value == htPrusaLink))
+        set_to_choice_and_config(htOctoPrint);
+    else
+        choice->set_value(m_config->option("host_type")->getInt());
+    had_all_mk3 = all_presets_are_from_mk3_family;
+}
+
 
 wxString PhysicalPrinterDialog::get_printer_name()
 {
@@ -628,8 +692,9 @@ void PhysicalPrinterDialog::AddPreset(wxEvent& event)
 
     m_presets_sizer->Add(m_presets.back()->sizer(), 1, wxEXPAND | wxTOP, BORDER_W);
     update_full_printer_names();
-
     this->Fit();
+
+    update_host_type(true);
 }
 
 void PhysicalPrinterDialog::DeletePreset(PresetForPrinter* preset_for_printer)
@@ -657,7 +722,8 @@ void PhysicalPrinterDialog::DeletePreset(PresetForPrinter* preset_for_printer)
 
     this->Layout();
     this->Fit();
+
+    update_host_type(true);
 }
 
-
 }}    // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp
index 7ee1f7d92..cb9a48b3e 100644
--- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp
+++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp
@@ -85,7 +85,8 @@ public:
     PhysicalPrinterDialog(wxWindow* parent, wxString printer_name);
     ~PhysicalPrinterDialog();
 
-    void        update();
+    void        update(bool printer_change = false);
+    void        update_host_type(bool printer_change);
     void        update_printhost_buttons();
     void        update_printers();
     wxString    get_printer_name();
@@ -95,10 +96,11 @@ public:
     PrinterTechnology   get_printer_technology();
 
     void        DeletePreset(PresetForPrinter* preset_for_printer);
-
 protected:
     void on_dpi_changed(const wxRect& suggested_rect) override;
     void on_sys_color_changed() override {};
+
+    bool had_all_mk3;
 };
 
 
diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp
index fad45f822..f01e3ad41 100644
--- a/src/slic3r/Utils/OctoPrint.cpp
+++ b/src/slic3r/Utils/OctoPrint.cpp
@@ -213,4 +213,48 @@ void SL1Host::set_auth(Http &http) const
     }
 }
 
+// PrusaLink
+PrusaLink::PrusaLink(DynamicPrintConfig* config) :
+    OctoPrint(config),
+    authorization_type(dynamic_cast<const ConfigOptionEnum<AuthorizationType>*>(config->option("printhost_authorization_type"))->value),
+    username(config->opt_string("printhost_user")),
+    password(config->opt_string("printhost_password"))
+{
+}
+
+const char* PrusaLink::get_name() const { return "PrusaLink"; }
+
+wxString PrusaLink::get_test_ok_msg() const
+{
+    return _(L("Connection to PrusaLink works correctly."));
+}
+
+wxString PrusaLink::get_test_failed_msg(wxString& msg) const
+{
+    return GUI::from_u8((boost::format("%s: %s")
+        % _utf8(L("Could not connect to PrusaLink"))
+        % std::string(msg.ToUTF8())).str());
+}
+
+bool PrusaLink::validate_version_text(const boost::optional<std::string>& version_text) const
+{
+    return version_text ? (boost::starts_with(*version_text, "PrusaLink") || boost::starts_with(*version_text, "OctoPrint")) : false;
+}
+
+void PrusaLink::set_auth(Http& http) const
+{
+    switch (authorization_type) {
+    case atKeyPassword:
+        http.header("X-Api-Key", get_apikey());
+        break;
+    case atUserPassword:
+        http.auth_digest(username, password);
+        break;
+    }
+
+    if (!get_cafile().empty()) {
+        http.ca_file(get_cafile());
+    }
+}
+
 }
diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp
index f1b36096c..62bdfb6fa 100644
--- a/src/slic3r/Utils/OctoPrint.hpp
+++ b/src/slic3r/Utils/OctoPrint.hpp
@@ -70,6 +70,31 @@ private:
     std::string password;
 };
 
+class PrusaLink : public OctoPrint
+{
+public:
+    PrusaLink(DynamicPrintConfig* config);
+    ~PrusaLink() override = default;
+
+    const char* get_name() const override;
+
+    wxString get_test_ok_msg() const override;
+    wxString get_test_failed_msg(wxString& msg) const override;
+    bool can_start_print() const override { return true; }
+
+protected:
+    bool validate_version_text(const boost::optional<std::string>& version_text) const override;
+
+private:
+    void set_auth(Http& http) const override;
+
+    // Host authorization type.
+    AuthorizationType authorization_type;
+    // username and password for HTTP Digest Authentization (RFC RFC2617)
+    std::string username;
+    std::string password;
+};
+
 }
 
 #endif
diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp
index 589679e47..53200a4c9 100644
--- a/src/slic3r/Utils/PrintHost.cpp
+++ b/src/slic3r/Utils/PrintHost.cpp
@@ -50,6 +50,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
             case htFlashAir:  return new FlashAir(config);
             case htAstroBox:  return new AstroBox(config);
             case htRepetier:  return new Repetier(config);
+            case htPrusaLink: return new PrusaLink(config);
             default:          return nullptr;
         }
     } else {