diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index d8ef62c04eec11d6bd1217a10b6925fb300a6889..d632e1f72132dcbb93210ddbdd236da95e062e94 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -84,6 +84,7 @@ static volatile BOOL	terminate_server=FALSE;
 static char 	*text[TOTAL_TEXT];
 static str_list_t recycle_semfiles;
 static str_list_t shutdown_semfiles;
+static link_list_t current_connections;
 
 #ifdef SOCKET_DEBUG
 	static BYTE 	socket_debug[0x10000]={0};
@@ -203,12 +204,15 @@ static void update_clients(void)
 
 static void client_on(SOCKET sock, client_t* client, BOOL update)
 {
+	if(!update)
+		listAddNodeData(&current_connections, client->addr, strlen(client->addr) + 1, sock, LAST_NODE);
 	if(startup!=NULL && startup->client_on!=NULL)
 		startup->client_on(startup->cbdata,TRUE,sock,client,update);
 }
 
 static void client_off(SOCKET sock)
 {
+	listRemoveTaggedNode(&current_connections, sock, /* free_data */TRUE);
 	if(startup!=NULL && startup->client_on!=NULL)
 		startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
 }
@@ -5029,6 +5033,8 @@ static void cleanup(int code, int line)
 
 	update_clients();	/* active_clients is destroyed below */
 
+	listFree(&current_connections);
+
 	if(protected_uint32_value(active_clients))
 		lprintf(LOG_WARNING,"!!!! Terminating with %d active clients", protected_uint32_value(active_clients));
 	else
@@ -5117,6 +5123,7 @@ void DLLCALL ftp_server(void* arg)
 	protected_uint32_init(&thread_count, 0);
 
 	do {
+		listInit(&current_connections, LINK_LIST_MUTEX);
 		protected_uint32_init(&active_clients, 0);
 
 		/* Setup intelligent defaults */
@@ -5295,6 +5302,20 @@ void DLLCALL ftp_server(void* arg)
 				startup->socket_open(startup->cbdata,TRUE);
 
 			inet_addrtop(&client_addr, client_ip, sizeof(client_ip));
+
+			if(startup->max_concurrent_connections > 0) {
+				int ip_len = strlen(client_ip) + 1;
+				uint connections = listCountMatches(&current_connections, client_ip, ip_len);
+				if(connections >= startup->max_concurrent_connections
+					&& !is_host_exempt(&scfg, client_ip, /* host_name */NULL)) {
+					lprintf(LOG_NOTICE, "%04d [%s] !Maximum concurrent connections (%u) exceeded"
+ 						,client_socket, client_ip, startup->max_concurrent_connections);
+					sockprintf(client_socket, -1, "421 Maximum connections (%u) exceeded", startup->max_concurrent_connections);
+					ftp_close_socket(&client_socket,&none,__LINE__);
+					continue;
+				}
+			}
+
 			if(trashcan(&scfg,client_ip,"ip-silent")) {
 				ftp_close_socket(&client_socket,&none,__LINE__);
 				continue;
diff --git a/src/sbbs3/ftpsrvr.h b/src/sbbs3/ftpsrvr.h
index e83599d978f13e54b74bf4aafad6c84570c6ae99..d9a0a2d1d0a71877df03197c6c640e1708bd6e07 100644
--- a/src/sbbs3/ftpsrvr.h
+++ b/src/sbbs3/ftpsrvr.h
@@ -83,6 +83,8 @@ typedef struct {
 	struct login_attempt_settings login_attempt;
 	link_list_t* login_attempt_list;
 
+	uint	max_concurrent_connections;
+
 } ftp_startup_t;
 
 /* startup options that requires re-initialization/recycle when changed */
diff --git a/src/sbbs3/sbbs_ini.c b/src/sbbs3/sbbs_ini.c
index d754f5b50f3aa4eec830371472f1d88738c73e63..bd9011be7d232a9b0582e331816da1e80a6d1c4c 100644
--- a/src/sbbs3/sbbs_ini.c
+++ b/src/sbbs3/sbbs_ini.c
@@ -39,6 +39,7 @@ static const char*	strInterfaces="Interface";
 static const char*	strPort="Port";
 static const char*	strMaxClients="MaxClients";
 static const char*	strMaxInactivity="MaxInactivity";
+static const char*	strMaxConConn="MaxConcurrentConnections";
 static const char*	strHostName="HostName";
 static const char*	strLogLevel="LogLevel";
 static const char*	strBindRetryCount="BindRetryCount";
@@ -391,7 +392,7 @@ void sbbs_read_ini(
 		bbs->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay);
 
 		bbs->login_attempt = get_login_attempt_settings(list, section, global);
-		bbs->max_concurrent_connections = iniGetInteger(list, section, "MaxConcurrentConnections", 0);
+		bbs->max_concurrent_connections = iniGetInteger(list, section, strMaxConConn, 0);
 	}
 
 	/***********************************************************************/
@@ -459,6 +460,7 @@ void sbbs_read_ini(
 		ftp->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count);
 		ftp->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay);
 		ftp->login_attempt = get_login_attempt_settings(list, section, global);
+		ftp->max_concurrent_connections = iniGetInteger(list, section, strMaxConConn, 0);
 	}
 
 	/***********************************************************************/
@@ -563,7 +565,7 @@ void sbbs_read_ini(
 		mail->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count);
 		mail->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay);
 		mail->login_attempt = get_login_attempt_settings(list, section, global);
-		mail->max_concurrent_connections = iniGetInteger(list, section, "MaxConcurrentConnections", 0);
+		mail->max_concurrent_connections = iniGetInteger(list, section, strMaxConConn, 0);
 	}
 
 	/***********************************************************************/
@@ -801,7 +803,7 @@ BOOL sbbs_write_ini(
 			break;
 		if(!iniSetShortInt(lp,section,"OutbufDrainTimeout",bbs->outbuf_drain_timeout,&style))
 			break;
-		if(!iniSetInteger(lp,section,"MaxConcurrentConnections",bbs->max_concurrent_connections,&style))
+		if(!iniSetInteger(lp,section,strMaxConConn,bbs->max_concurrent_connections,&style))
 			break;
 
 
@@ -886,6 +888,8 @@ BOOL sbbs_write_ini(
 			break;
 		if(!iniSetShortInt(lp,section,strMaxInactivity,ftp->max_inactivity,&style))
 			break;
+		if(!iniSetInteger(lp,section,strMaxConConn,ftp->max_concurrent_connections,&style))
+			break;
 		if(!iniSetShortInt(lp,section,"QwkTimeout",ftp->qwk_timeout,&style))
 			break;
 		if(!iniSetBytes(lp,section,"MinFileSize",1,ftp->min_fsize,&style))
@@ -1010,7 +1014,7 @@ BOOL sbbs_write_ini(
 			break;
 		if(!iniSetInteger(lp,section,"ConnectTimeout",mail->connect_timeout,&style))
 			break;
-		if(!iniSetInteger(lp,section,"MaxConcurrentConnections",mail->max_concurrent_connections,&style))
+		if(!iniSetInteger(lp,section,strMaxConConn,mail->max_concurrent_connections,&style))
 			break;
 
 		if(strcmp(mail->host_name,global->host_name)==0