diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 7c9403382..6d588075d 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -3,6 +3,7 @@
 #include "AppConfig.hpp"
 #include "Exception.hpp"
 #include "Thread.hpp"
+#include "format.hpp"
 
 #include <utility>
 #include <vector>
@@ -16,9 +17,13 @@
 #include <boost/property_tree/ptree_fwd.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/format/format_fwd.hpp>
+#include <boost/log/trivial.hpp>
 
-//#include <wx/string.h>
-//#include "I18N.hpp"
+#ifdef WIN32
+//FIXME replace the two following includes with <boost/md5.hpp> after it becomes mainstream.
+#include <boost/uuid/detail/md5.hpp>
+#include <boost/algorithm/hex.hpp>
+#endif
 
 namespace Slic3r {
 
@@ -164,25 +169,114 @@ void AppConfig::set_defaults()
     erase("", "object_settings_size");
 }
 
+#ifdef WIN32
+static std::string appconfig_md5_hash_line(const std::string_view data)
+{
+    //FIXME replace the two following includes with <boost/md5.hpp> after it becomes mainstream.
+    // return boost::md5(data).hex_str_value();
+    // boost::uuids::detail::md5 is an internal namespace thus it may change in the future.
+    // Also this implementation is not the fastest, it was designed for short blocks of text.
+    using boost::uuids::detail::md5;
+    md5              md5_hash;
+    // unsigned int[4], 128 bits
+    md5::digest_type md5_digest{};
+    std::string      md5_digest_str;
+    md5_hash.process_bytes(data.data(), data.size());
+    md5_hash.get_digest(md5_digest);
+    boost::algorithm::hex(md5_digest, md5_digest + std::size(md5_digest), std::back_inserter(md5_digest_str));
+    // MD5 hash is 32 HEX digits long.
+    assert(md5_digest_str.size() == 32);
+    // This line will be emited at the end of the file.
+    return "# MD5 checksum " + md5_digest_str + "\n";
+};
+
+// Assume that the last line with the comment inside the config file contains a checksum and that the user didn't modify the config file.
+static bool verify_config_file_checksum(boost::nowide::ifstream &ifs)
+{
+    auto read_whole_config_file = [&ifs]() -> std::string {
+        std::stringstream ss;
+        ss << ifs.rdbuf();
+        return ss.str();
+    };
+
+    ifs.seekg(0, boost::nowide::ifstream::beg);
+    std::string whole_config = read_whole_config_file();
+
+    // The checksum should be on the last line in the config file.
+    if (size_t last_comment_pos = whole_config.find_last_of('#'); last_comment_pos != std::string::npos) {
+        // Split read config into two parts, one with checksum, and the second part is part with configuration from the checksum was computed.
+        // Verify existence and validity of the MD5 checksum line at the end of the file.
+        // When the checksum isn't found, the checksum was not saved correctly, it was removed or it is an older config file without the checksum.
+        // If the checksum is incorrect, then the file was either not saved correctly or modified.
+        if (std::string_view(whole_config.c_str() + last_comment_pos, whole_config.size() - last_comment_pos) == appconfig_md5_hash_line({ whole_config.data(), last_comment_pos }))
+            return true;
+    }
+    return false;
+}
+#endif
+
 std::string AppConfig::load()
 {
     // 1) Read the complete config file into a boost::property_tree.
     namespace pt = boost::property_tree;
     pt::ptree tree;
-    boost::nowide::ifstream ifs(AppConfig::config_path());
+    boost::nowide::ifstream ifs;
+    bool                    recovered = false;
+
     try {
+        ifs.open(AppConfig::config_path());
+#ifdef WIN32
+        // Verify the checksum of the config file without taking just for debugging purpose.
+        if (!verify_config_file_checksum(ifs))
+            BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::config_path() <<
+            " has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit.";
+
+        ifs.seekg(0, boost::nowide::ifstream::beg);
+#endif
         pt::read_ini(ifs, tree);
     } catch (pt::ptree_error& ex) {
-        // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
-        // ! But to avoid the use of _utf8 (related to use of wxWidgets) 
-        // we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
-        /*
-        throw Slic3r::RuntimeError(
-        	_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
-                    "Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) + 
-        	"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
-        */
-        return ex.what();
+#ifdef WIN32
+        // The configuration file is corrupted, try replacing it with the backup configuration.
+        ifs.close();
+        std::string backup_path = (boost::format("%1%.bak") % AppConfig::config_path()).str();
+        if (boost::filesystem::exists(backup_path)) {
+            // Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct.
+            boost::nowide::ifstream backup_ifs(backup_path);
+            if (!verify_config_file_checksum(backup_ifs)) {
+                BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::config_path(), backup_path);
+                backup_ifs.close();
+                boost::filesystem::remove(backup_path);
+            } else if (std::string error_message; copy_file(backup_path, AppConfig::config_path(), error_message, false) != SUCCESS) {
+                BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::config_path(), backup_path, error_message);
+                backup_ifs.close();
+                boost::filesystem::remove(backup_path);
+            } else {
+                BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::config_path(), backup_path);
+                // Try parse configuration file after restore from backup.
+                try {
+                    ifs.open(AppConfig::config_path());
+                    pt::read_ini(ifs, tree);
+                    recovered = true;
+                } catch (pt::ptree_error& ex) {
+                    BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::config_path(), ex.what());
+                }
+            }
+        } else
+#endif // WIN32
+            BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::config_path(), ex.what());
+        if (! recovered) {
+            // Report the initial error of parsing PrusaSlicer.ini.
+            // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
+            // ! But to avoid the use of _utf8 (related to use of wxWidgets) 
+            // we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
+            /*
+            throw Slic3r::RuntimeError(
+                _utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
+                        "Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) +
+                "\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
+            */
+            return ex.what();
+        }
     }
 
     // 2) Parse the property_tree, extract the sections and key / value pairs.
@@ -259,22 +353,21 @@ void AppConfig::save()
     const auto path = config_path();
     std::string path_pid = (boost::format("%1%.%2%") % path % get_current_pid()).str();
 
-    boost::nowide::ofstream c;
-    c.open(path_pid, std::ios::out | std::ios::trunc);
+    std::stringstream config_ss;
     if (m_mode == EAppMode::Editor)
-        c << "# " << Slic3r::header_slic3r_generated() << std::endl;
+        config_ss << "# " << Slic3r::header_slic3r_generated() << std::endl;
     else
-        c << "# " << Slic3r::header_gcodeviewer_generated() << std::endl;
+        config_ss << "# " << Slic3r::header_gcodeviewer_generated() << std::endl;
     // Make sure the "no" category is written first.
-    for (const std::pair<std::string, std::string> &kvp : m_storage[""])
-        c << kvp.first << " = " << kvp.second << std::endl;
+    for (const auto& kvp : m_storage[""])
+        config_ss << kvp.first << " = " << kvp.second << std::endl;
     // Write the other categories.
     for (const auto category : m_storage) {
     	if (category.first.empty())
     		continue;
-    	c << std::endl << "[" << category.first << "]" << std::endl;
-    	for (const std::pair<std::string, std::string> &kvp : category.second)
-	        c << kvp.first << " = " << kvp.second << std::endl;
+        config_ss << std::endl << "[" << category.first << "]" << std::endl;
+        for (const auto& kvp : category.second)
+            config_ss << kvp.first << " = " << kvp.second << std::endl;
 	}
     // Write vendor sections
     for (const auto &vendor : m_vendors) {
@@ -282,17 +375,42 @@ void AppConfig::save()
         for (const auto &model : vendor.second) { size_sum += model.second.size(); }
         if (size_sum == 0) { continue; }
 
-        c << std::endl << "[" << VENDOR_PREFIX << vendor.first << "]" << std::endl;
+        config_ss << std::endl << "[" << VENDOR_PREFIX << vendor.first << "]" << std::endl;
 
         for (const auto &model : vendor.second) {
-            if (model.second.size() == 0) { continue; }
+            if (model.second.empty()) { continue; }
             const std::vector<std::string> variants(model.second.begin(), model.second.end());
             const auto escaped = escape_strings_cstyle(variants);
-            c << MODEL_PREFIX << model.first << " = " << escaped << std::endl;
+            config_ss << MODEL_PREFIX << model.first << " = " << escaped << std::endl;
         }
     }
-    c.close();
+    // One empty line before the MD5 sum.
+    config_ss << std::endl;
 
+    std::string config_str = config_ss.str();
+    boost::nowide::ofstream c;
+    c.open(path_pid, std::ios::out | std::ios::trunc);
+    c << config_str;
+#ifdef WIN32
+    // WIN32 specific: The final "rename_file()" call is not safe in case of an application crash, there is no atomic "rename file" API
+    // provided by Windows (sic!). Therefore we save a MD5 checksum to be able to verify file corruption. In addition,
+    // we save the config file into a backup first before moving it to the final destination.
+    c << appconfig_md5_hash_line(config_str);
+#endif
+    c.close();
+    
+#ifdef WIN32
+    // Make a backup of the configuration file before copying it to the final destination.
+    std::string error_message;
+    std::string backup_path = (boost::format("%1%.bak") % path).str();
+    // Copy configuration file with PID suffix into the configuration file with "bak" suffix.
+    if (copy_file(path_pid, backup_path, error_message, false) != SUCCESS)
+        BOOST_LOG_TRIVIAL(error) << "Copying from " << path_pid << " to " << backup_path << " failed. Failed to create a backup configuration.";
+#endif
+
+    // Rename the config atomically.
+    // On Windows, the rename is likely NOT atomic, thus it may fail if PrusaSlicer crashes on another thread in the meanwhile.
+    // To cope with that, we already made a backup of the config on Windows.
     rename_file(path_pid, path);
     m_dirty = false;
 }
diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp
index c8ccd18cd..0a53a5330 100644
--- a/src/libslic3r/AppConfig.hpp
+++ b/src/libslic3r/AppConfig.hpp
@@ -37,7 +37,7 @@ public:
 
 	// Load the slic3r.ini from a user profile directory (or a datadir, if configured).
 	// return error string or empty strinf
-	std::string		   	load();
+	std::string         load();
 	// Store the slic3r.ini into a user profile directory (or a datadir, if configured).
 	void 			   	save();