diff --git a/CHANGES b/CHANGES
index 21c09ed0e59deadefecbeb86ca866fb34bff360c..b66729305d1b9778a662c321ee36e5b834aed6f6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,9 @@ Version 4.0.0 differs from 3.2.x in the following ways:
 -- Add SOCI_FIREBIRD_EMBEDDED option to allow building with embedded library.
 -- Throw an exception instead of truncating too long VARCHAR columns values.
 
+- ODBC/MS SQL
+-- Fix inserting strings of length greater than 8000 bytes into database.
+
 - Oracle
 -- Use SQLT_BDOUBLE for floating point values instead of SQLT_FLT.
 
diff --git a/src/backends/odbc/standard-use-type.cpp b/src/backends/odbc/standard-use-type.cpp
index d32c5b749a0c5f85cfd43edfc00c23139ee75c39..f5b126ec0536702f9f69861f86424ba98dce9c02 100644
--- a/src/backends/odbc/standard-use-type.cpp
+++ b/src/backends/odbc/standard-use-type.cpp
@@ -99,6 +99,15 @@ void* odbc_standard_use_type_backend::prepare_for_bind(
         memcpy(buf_, s.c_str(), size);
         buf_[size++] = '\0';
         indHolder_ = SQL_NTS;
+
+        // Strings of greater length are silently truncated at 8000 limit by MS
+        // SQL unless SQL_SS_LENGTH_UNLIMITED (which is defined as 0, but not
+        // available in all headers) is used.
+        if (size > 8000)
+        {
+          sqlType = SQL_LONGVARCHAR;
+          size = 0 /* SQL_SS_LENGTH_UNLIMITED */;
+        }
     }
     break;
     case x_stdtm:
diff --git a/tests/odbc/test-odbc-mssql.cpp b/tests/odbc/test-odbc-mssql.cpp
index 479ffedf9783b5678ef74706e1bbf461cfe9f032..f4511c9ebe929d9fe8bb8819873fb71877e57870 100644
--- a/tests/odbc/test-odbc-mssql.cpp
+++ b/tests/odbc/test-odbc-mssql.cpp
@@ -19,6 +19,60 @@ using namespace soci::tests;
 std::string connectString;
 backend_factory const &backEnd = *soci::factory_odbc();
 
+// MS SQL-specific tests
+TEST_CASE("MS SQL long string", "[odbc][mssql][long]")
+{
+    session sql(backEnd, connectString);
+
+    struct long_text_table_creator : public table_creator_base
+    {
+        explicit long_text_table_creator(session& sql)
+            : table_creator_base(sql)
+        {
+            // Notice that 4000 is the maximal length of an nvarchar() column,
+            // at least when using FreeTDS ODBC driver.
+            sql << "create table soci_test ("
+                        "long_text nvarchar(max) null, "
+                        "fixed_text nvarchar(4000) null"
+                    ")";
+        }
+    } long_text_table_creator(sql);
+
+    // Build a string at least 8000 characters long to test that it survives
+    // the round trip unscathed.
+    std::ostringstream os;
+    for ( int n = 0; n < 1000; ++n )
+    {
+        os << "Line #" << n << "\n";
+    }
+
+    std::string const str_in = os.str();
+    sql << "insert into soci_test(long_text) values(:str)", use(str_in);
+
+    std::string str_out;
+    sql << "select long_text from soci_test", into(str_out);
+
+    // Don't just compare the strings because the error message in case they
+    // differ is completely unreadable due to their size, so give a better
+    // error in the common failure case.
+    if (str_out.length() != str_in.length())
+    {
+        FAIL("Read back string of length " << str_out.length() <<
+             " instead of expected " << str_in.length());
+    }
+    else
+    {
+        CHECK(str_out == str_in);
+    }
+
+    // The long string should be truncated when inserting it into a fixed size
+    // column.
+    CHECK_THROWS_AS(
+        (sql << "insert into soci_test(fixed_text) values(:str)", use(str_in)),
+        soci_error
+    );
+}
+
 // DDL Creation objects for common tests
 struct table_creator_one : public table_creator_base
 {