diff --git a/src/ssb.c b/src/ssb.c
index 739d927b..aa05a5a1 100644
--- a/src/ssb.c
+++ b/src/ssb.c
@@ -248,6 +248,8 @@ typedef struct _tf_ssb_t
 	bool is_replicator;
 	bool is_peer_exchange;
 	bool talk_to_strangers;
+	bool broadcast;
+	bool discovery;
 	char* room_name;
 	char seeds_host[256];
 	time_t last_seed_check;
@@ -3376,6 +3378,12 @@ static void _tf_ssb_update_seeds_after_work(tf_ssb_t* ssb, int status, void* use
 static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
 {
 	tf_ssb_t* ssb = timer->data;
+	if (!ssb->broadcast)
+	{
+		uv_timer_stop(timer);
+		return;
+	}
+
 	uv_interface_address_t* info = NULL;
 	int count = 0;
 	if (uv_interface_addresses(&info, &count) == 0)
@@ -3605,13 +3613,13 @@ void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcas
 
 static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
 {
-	if (nread <= 0)
+	tf_ssb_t* ssb = handle->data;
+	if (nread <= 0 || !ssb->discovery)
 	{
 		tf_free(buf->base);
 		return;
 	}
 
-	tf_ssb_t* ssb = handle->data;
 	((char*)buf->base)[nread] = '\0';
 
 	const char* k_delim = ";";
@@ -3714,7 +3722,7 @@ void tf_ssb_broadcast_listener_start(tf_ssb_t* ssb, bool linger)
 
 void tf_ssb_broadcast_sender_start(tf_ssb_t* ssb)
 {
-	if (ssb->broadcast_sender.data)
+	if (ssb->broadcast_sender.data || !ssb->broadcast)
 	{
 		return;
 	}
@@ -4428,6 +4436,8 @@ typedef struct _update_settings_t
 	bool is_replicator;
 	bool is_peer_exchange;
 	bool talk_to_strangers;
+	bool broadcast;
+	bool discovery;
 	char seeds_host[256];
 	char room_name[1024];
 } update_settings_t;
@@ -4440,12 +4450,16 @@ static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
 	update->is_replicator = true;
 	update->is_peer_exchange = true;
 	update->talk_to_strangers = true;
+	update->broadcast = true;
+	update->discovery = true;
 	tf_ssb_db_get_global_setting_bool(db, "room", &update->is_room);
 	tf_ssb_db_get_global_setting_bool(db, "replicator", &update->is_replicator);
 	tf_ssb_db_get_global_setting_bool(db, "peer_exchange", &update->is_peer_exchange);
 	tf_ssb_db_get_global_setting_bool(db, "talk_to_strangers", &update->talk_to_strangers);
 	tf_ssb_db_get_global_setting_string(db, "room_name", update->room_name, sizeof(update->room_name));
 	tf_ssb_db_get_global_setting_string(db, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
+	tf_ssb_db_get_global_setting_bool(db, "broadcast", &update->broadcast);
+	tf_ssb_db_get_global_setting_bool(db, "discovery", &update->discovery);
 	tf_ssb_release_db_reader(ssb, db);
 }
 
@@ -4457,6 +4471,12 @@ static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void*
 	tf_ssb_set_is_peer_exchange(ssb, update->is_peer_exchange);
 	tf_ssb_set_is_replicator(ssb, update->is_replicator);
 	ssb->talk_to_strangers = update->talk_to_strangers;
+	ssb->broadcast = update->broadcast;
+	if (ssb->broadcast && tf_ssb_server_get_port(ssb) && !uv_timer_get_due_in(&ssb->broadcast_timer))
+	{
+		uv_timer_start(&ssb->broadcast_timer, _tf_ssb_broadcast_timer, 2000, 2000);
+	}
+	ssb->discovery = update->discovery;
 	snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
 	_tf_ssb_start_update_settings(ssb);
 	tf_free(update);
diff --git a/src/util.js.c b/src/util.js.c
index 2b9ef128..947ce37d 100644
--- a/src/util.js.c
+++ b/src/util.js.c
@@ -398,6 +398,8 @@ static const setting_t k_settings[] = {
 		.description = "Whether connections are accepted from accounts that aren't in the replication range or otherwise already known.",
 		.default_value = { .kind = k_kind_bool, .bool_value = true } },
 	{ .name = "autologin", .type = "boolean", .description = "Whether mobile autologin is supported.", .default_value = { .kind = k_kind_bool, .bool_value = TF_IS_MOBILE != 0 } },
+	{ .name = "broadcast", .type = "boolean", .description = "Send network discovery broadcasts.", .default_value = { .kind = k_kind_bool, .bool_value = true } },
+	{ .name = "discovery", .type = "boolean", .description = "Receive network discovery broadcasts.", .default_value = { .kind = k_kind_bool, .bool_value = true } },
 };
 
 static const setting_t* _util_get_setting(const char* name, tf_setting_kind_t kind)