diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index 55892108e23cb9876b7b576c1a6ae521bb328520..d47e56699c9f4418c7ecedf845c5530ae9fd2e37 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -1169,6 +1169,14 @@ static BOOL start_tls(SOCKET *sock, CRYPT_SESSION *sess, BOOL resp)
 			sockprintf(*sock, *sess, "431 TLS not available");
 		return FALSE;
 	}
+	if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_MINVER_TLS12)) != CRYPT_OK) {
+		GCES(status, *sock, *sess, estr, "setting TLS minver");
+		cryptDestroySession(*sess);
+		*sess = -1;
+		if(resp)
+			sockprintf(*sock, *sess, "431 TLS not available");
+		return FALSE;
+	}
 	if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 		GCES(status, *sock, *sess, estr, "disabling certificate verification");
 		cryptDestroySession(*sess);
diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index e6429e6250c11980af52911f2eeda7b06bd35470..a8f2eb1e77848c3a012306c01995ff7812039c7f 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -2250,6 +2250,7 @@ enum {
 	,SOCK_PROP_NETWORK_ORDER
 	,SOCK_PROP_SSL_SESSION
 	,SOCK_PROP_SSL_SERVER
+	,SOCK_PROP_TLS_MINVER
 
 };
 
@@ -2275,6 +2276,7 @@ static const char* socket_prop_desc[] = {
 	,"<tt>true</tt> if binary data is to be sent in Network Byte Order (big end first), default is <tt>true</tt>"
 	,"Set to <tt>true</tt> to enable SSL as a client on the socket"
 	,"Set to <tt>true</tt> to enable SSL as a server on the socket"
+	,"Set to 100 to support TLS 1.0, 101 to support TLS 1.1 and 102 (default) for TLS 1.2, must be set before enabling TLS"
 
 	/* statically-defined properties: */
 	,"Array of socket option names supported by the current platform"
@@ -2355,6 +2357,12 @@ static JSBool js_socket_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict
 							nb=1;
 							setsockopt(p->sock,IPPROTO_TCP,TCP_NODELAY,(char*)&nb,sizeof(nb));
 							if((ret=do_cryptAttribute(p->session, CRYPT_SESSINFO_NETWORKSOCKET, p->sock))==CRYPT_OK) {
+								int minver = CRYPT_TLSOPTION_MINVER_TLS12;
+								if (p->tls_minver == 100)
+									minver = CRYPT_TLSOPTION_MINVER_TLS10;
+								else if (p->tls_minver == 101)
+									minver = CRYPT_TLSOPTION_MINVER_TLS11;
+								do_cryptAttribute(p->session, CRYPT_SESSINFO_TLS_OPTIONS, minver);
 								// Reduced compliance checking... required for acme-staging-v02.api.letsencrypt.org
 								do_cryptAttribute(p->session, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_REDUCED);
 								if (tiny == SOCK_PROP_SSL_SESSION) {
@@ -2406,6 +2414,17 @@ static JSBool js_socket_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict
 			}
 			JS_RESUMEREQUEST(cx, rc);
 			break;
+		case SOCK_PROP_TLS_MINVER:
+			if(JS_ValueToInt32(cx,*vp,&i)) {
+				switch(i) {
+					case 100:
+					case 101:
+					case 102:
+						p->tls_minver = i;
+						break;
+				}
+			}
+			break;
 	}
 
 	return(JS_TRUE);
@@ -2568,6 +2587,9 @@ static JSBool js_socket_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 		case SOCK_PROP_SSL_SERVER:
 			*vp = BOOLEAN_TO_JSVAL(p->session != -1 && p->tls_server);
 			break;
+		case SOCK_PROP_TLS_MINVER:
+			*vp = INT_TO_JSVAL(p->tls_minver);
+			break;
 	}
 
 	JS_RESUMEREQUEST(cx, rc);
@@ -2599,6 +2621,7 @@ static jsSyncPropertySpec js_socket_properties[] = {
 	{	"network_byte_order",SOCK_PROP_NETWORK_ORDER,JSPROP_ENUMERATE,	311 },
 	{	"ssl_session"		,SOCK_PROP_SSL_SESSION	,JSPROP_ENUMERATE,	316	},
 	{	"ssl_server"		,SOCK_PROP_SSL_SERVER	,JSPROP_ENUMERATE,	316	},
+	{	"tls_minver"		,SOCK_PROP_TLS_MINVER	,JSPROP_ENUMERATE,	320	},
 	{0}
 };
 
@@ -2834,6 +2857,7 @@ JSObject* js_CreateSocketObjectWithoutParent(JSContext* cx, SOCKET sock, CRYPT_C
 	p->network_byte_order = TRUE;
 	p->session=session;
 	p->unflushed = 0;
+	p->tls_minver = 102;
 
 	if (p->sock != INVALID_SOCKET) {
 		len=sizeof(p->remote_addr);
@@ -3192,6 +3216,7 @@ connected:
 	p->session=-1;
 	p->unflushed = 0;
 	p->is_connected = TRUE;
+	p->tls_minver = 102;
 
 	if(!JS_SetPrivate(cx, obj, p)) {
 		JS_ReportError(cx,"JS_SetPrivate failed");
@@ -3384,6 +3409,7 @@ js_listening_socket_constructor(JSContext *cx, uintN argc, jsval *arglist)
 	p->session=-1;
 	p->unflushed = 0;
 	p->local_port = port;
+	p->tls_minver = 102;
 
 	if(!JS_SetPrivate(cx, obj, p)) {
 		JS_ReportError(cx,"JS_SetPrivate failed");
@@ -3497,6 +3523,7 @@ js_socket_constructor(JSContext *cx, uintN argc, jsval *arglist)
 	p->network_byte_order = TRUE;
 	p->session=-1;
 	p->unflushed = 0;
+	p->tls_minver = 102;
 
 	if(!JS_SetPrivate(cx, obj, p)) {
 		JS_ReportError(cx,"JS_SetPrivate failed");
@@ -3618,6 +3645,7 @@ JSObject* js_CreateSocketObjectFromSet(JSContext* cx, JSObject* parent, char *na
 	p->network_byte_order = TRUE;
 	p->session=-1;
 	p->unflushed = 0;
+	p->tls_minver = 102;
 
 	if(!JS_SetPrivate(cx, obj, p)) {
 		dbprintf(TRUE, p, "JS_SetPrivate failed");
diff --git a/src/sbbs3/js_socket.h b/src/sbbs3/js_socket.h
index 8e5acce615d6cc0bed466172d073a9c8f8cc4142..a42da28d75f23ed10081a1b45d98d1bd61f61baf 100644
--- a/src/sbbs3/js_socket.h
+++ b/src/sbbs3/js_socket.h
@@ -26,6 +26,7 @@ typedef struct
 	BOOL	peeked;
 	uint16_t local_port;
 	js_callback_t *js_cb;
+	int     tls_minver;
 } js_socket_private_t;
 
 #ifdef __cplusplus
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 29cc542ae99b639ef25095153ac2c9b1f53bd68d..72e48d254e41bac430e07b3782534df1839c0212 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -1097,6 +1097,7 @@ static void js_service_thread(void* arg)
 			js_service_failure_cleanup(service, socket);
 			return;
 		}
+		HANDLE_CRYPT_CALL(cryptSetAttribute(service_client.tls_sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_MINVER_TLS12), &service_client, "setting minimum TLS version");
 		/* Add all the user/password combinations */
 #if 0 // TLS-PSK is currently broken in cryptlib
 		last = lastuser(&scfg);