diff --git a/crates/core/config/Revolt.toml b/crates/core/config/Revolt.toml
index 9f5c0c262..3fa1fe804 100644
--- a/crates/core/config/Revolt.toml
+++ b/crates/core/config/Revolt.toml
@@ -48,6 +48,7 @@ webhooks_enabled = false
 
 [features.limits.global]
 group_size = 100
+message_embeds = 5
 message_replies = 5
 message_reactions = 20
 server_emoji = 100
@@ -61,7 +62,6 @@ outgoing_friend_requests = 5
 
 bots = 2
 message_length = 2000
-message_embeds = 5
 message_attachments = 5
 servers = 100
 
@@ -77,7 +77,6 @@ outgoing_friend_requests = 10
 
 bots = 5
 message_length = 2000
-message_embeds = 5
 message_attachments = 5
 servers = 100
 
diff --git a/crates/core/config/src/lib.rs b/crates/core/config/src/lib.rs
index 02d238dd6..701fc14d1 100644
--- a/crates/core/config/src/lib.rs
+++ b/crates/core/config/src/lib.rs
@@ -107,6 +107,7 @@ pub struct Api {
 #[derive(Deserialize, Debug, Clone)]
 pub struct GlobalLimits {
     pub group_size: usize,
+    pub message_embeds: usize,
     pub message_replies: usize,
     pub message_reactions: usize,
     pub server_emoji: usize,
@@ -123,7 +124,6 @@ pub struct FeaturesLimits {
     pub bots: usize,
     pub message_length: usize,
     pub message_attachments: usize,
-    pub message_embeds: usize,
     pub servers: usize,
 
     pub attachment_size: usize,
diff --git a/crates/core/database/src/models/bots/model.rs b/crates/core/database/src/models/bots/model.rs
index 6b2134328..cb36d0085 100644
--- a/crates/core/database/src/models/bots/model.rs
+++ b/crates/core/database/src/models/bots/model.rs
@@ -80,8 +80,7 @@ impl Bot {
             return Err(create_error!(IsBot));
         }
 
-        let config = config().await;
-        if db.get_number_of_bots_by_user(&owner.id).await? >= config.features.limits.default.bots {
+        if db.get_number_of_bots_by_user(&owner.id).await? >= owner.limits().await.bots {
             return Err(create_error!(ReachedMaximumBots));
         }
 
diff --git a/crates/core/database/src/models/messages/model.rs b/crates/core/database/src/models/messages/model.rs
index afafff91a..b46e73c79 100644
--- a/crates/core/database/src/models/messages/model.rs
+++ b/crates/core/database/src/models/messages/model.rs
@@ -2,7 +2,7 @@ use std::collections::HashSet;
 
 use indexmap::{IndexMap, IndexSet};
 use iso8601_timestamp::Timestamp;
-use revolt_config::config;
+use revolt_config::{config, FeaturesLimits};
 use revolt_models::v0::{
     self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageSort, MessageWebhook,
     PushNotification, ReplyIntent, SendableEmbed, Text, RE_MENTION,
@@ -207,11 +207,13 @@ impl Default for Message {
 #[allow(clippy::disallowed_methods)]
 impl Message {
     /// Create message from API data
+    #[allow(clippy::too_many_arguments)]
     pub async fn create_from_api(
         db: &Database,
         channel: Channel,
         data: DataMessageSend,
         author: MessageAuthor<'_>,
+        limits: FeaturesLimits,
         mut idempotency: IdempotencyKey,
         generate_embeds: bool,
         allow_mentions: bool,
@@ -221,7 +223,7 @@ impl Message {
         Message::validate_sum(
             &data.content,
             data.embeds.as_deref().unwrap_or_default(),
-            config.features.limits.default.message_length,
+            limits.message_length,
         )?;
 
         idempotency
@@ -320,20 +322,20 @@ impl Message {
         if data
             .attachments
             .as_ref()
-            .is_some_and(|v| v.len() > config.features.limits.default.message_attachments)
+            .is_some_and(|v| v.len() > limits.message_attachments)
         {
             return Err(create_error!(TooManyAttachments {
-                max: config.features.limits.default.message_attachments,
+                max: limits.message_attachments,
             }));
         }
 
         if data
             .embeds
             .as_ref()
-            .is_some_and(|v| v.len() > config.features.limits.default.message_embeds)
+            .is_some_and(|v| v.len() > config.features.limits.global.message_embeds)
         {
             return Err(create_error!(TooManyEmbeds {
-                max: config.features.limits.default.message_embeds,
+                max: config.features.limits.global.message_embeds,
             }));
         }
 
diff --git a/crates/core/database/src/models/users/model.rs b/crates/core/database/src/models/users/model.rs
index 1a3b9820b..c434291d8 100644
--- a/crates/core/database/src/models/users/model.rs
+++ b/crates/core/database/src/models/users/model.rs
@@ -1,10 +1,10 @@
-use std::{collections::HashSet, time::Duration};
+use std::{collections::HashSet, str::FromStr, time::Duration};
 
 use crate::{events::client::EventV1, Database, File, RatelimitEvent};
 
 use once_cell::sync::Lazy;
 use rand::seq::SliceRandom;
-use revolt_config::config;
+use revolt_config::{config, FeaturesLimits};
 use revolt_models::v0;
 use revolt_presence::filter_online;
 use revolt_result::{create_error, Result};
@@ -197,6 +197,22 @@ impl User {
         Ok(user)
     }
 
+    /// Get limits for this user
+    pub async fn limits(&self) -> FeaturesLimits {
+        let config = config().await;
+        if ulid::Ulid::from_str(&self.id)
+            .expect("`ulid`")
+            .datetime()
+            .elapsed()
+            .expect("time went backwards")
+            <= Duration::from_secs(86400u64 * config.features.limits.global.new_user_days as u64)
+        {
+            config.features.limits.new_user
+        } else {
+            config.features.limits.default
+        }
+    }
+
     /// Get the relationship with another user
     pub fn relationship_with(&self, user_b: &str) -> RelationshipStatus {
         if self.id == user_b {
@@ -235,12 +251,11 @@ impl User {
 
     /// Check if this user can acquire another server
     pub async fn can_acquire_server(&self, db: &Database) -> Result<()> {
-        let config = config().await;
-        if db.fetch_server_count(&self.id).await? <= config.features.limits.default.servers {
+        if db.fetch_server_count(&self.id).await? <= self.limits().await.servers {
             Ok(())
         } else {
             Err(create_error!(TooManyServers {
-                max: config.features.limits.default.servers
+                max: self.limits().await.servers
             }))
         }
     }
@@ -500,10 +515,9 @@ impl User {
                     .unwrap_or_default();
 
                 // If we're over the limit, don't allow creating more requests
-                let config = config().await;
-                if count >= config.features.limits.default.outgoing_friend_requests {
+                if count >= self.limits().await.outgoing_friend_requests {
                     return Err(create_error!(TooManyPendingFriendRequests {
-                        max: config.features.limits.default.outgoing_friend_requests
+                        max: self.limits().await.outgoing_friend_requests
                     }));
                 }
 
diff --git a/crates/core/database/src/tasks/process_embeds.rs b/crates/core/database/src/tasks/process_embeds.rs
index 459b8b3ad..d9d61d75a 100644
--- a/crates/core/database/src/tasks/process_embeds.rs
+++ b/crates/core/database/src/tasks/process_embeds.rs
@@ -56,7 +56,7 @@ pub async fn worker(db: Database) {
             let embeds = generate(
                 task.content,
                 &config.hosts.january,
-                config.features.limits.default.message_embeds,
+                config.features.limits.global.message_embeds,
                 semaphore,
             )
             .await;
diff --git a/crates/delta/src/routes/channels/message_edit.rs b/crates/delta/src/routes/channels/message_edit.rs
index 4c1a78b95..41958e34e 100644
--- a/crates/delta/src/routes/channels/message_edit.rs
+++ b/crates/delta/src/routes/channels/message_edit.rs
@@ -30,11 +30,10 @@ pub async fn edit(
         })
     })?;
 
-    let config = config().await;
     Message::validate_sum(
         &edit.content,
         edit.embeds.as_deref().unwrap_or_default(),
-        config.features.limits.default.message_length,
+        user.limits().await.message_length,
     )?;
 
     // Ensure we have permissions to send a message
diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs
index ab83be956..28b906519 100644
--- a/crates/delta/src/routes/channels/message_send.rs
+++ b/crates/delta/src/routes/channels/message_send.rs
@@ -81,6 +81,7 @@ pub async fn message_send(
             channel,
             data,
             v0::MessageAuthor::User(&author),
+            user.limits().await,
             idempotency,
             permissions.has_channel_permission(ChannelPermission::SendEmbeds),
             allow_mentions,
diff --git a/crates/delta/src/routes/webhooks/webhook_execute.rs b/crates/delta/src/routes/webhooks/webhook_execute.rs
index f370b1861..6a6eebc44 100644
--- a/crates/delta/src/routes/webhooks/webhook_execute.rs
+++ b/crates/delta/src/routes/webhooks/webhook_execute.rs
@@ -1,3 +1,4 @@
+use revolt_config::config;
 use revolt_database::{
     util::{idempotency::IdempotencyKey, reference::Reference},
     Database, Message,
@@ -58,6 +59,7 @@ pub async fn webhook_execute(
             channel,
             data,
             v0::MessageAuthor::Webhook(&webhook.into()),
+            config().await.features.limits.default,
             idempotency,
             true,
             true,