TL;DR, Quick Answer
7 min readUpstream Mastodon sets MAX_CHARS to 500 in a single Ruby file, and a server operator who edits that constant changes the limit for everyone on that server. Real servers run at 500, 1,000 and 11,000. The count is in grapheme clusters, so a family emoji costs 1, every URL is billed at a flat 23 characters no matter how long it is, and the content warning field is added to the total. Read configuration.statuses.max_characters from a server's /api/v2/instance endpoint instead of assuming 500.
What is the Mastodon character limit?
Upstream Mastodon sets the Mastodon character limit at 500 grapheme clusters, and any server operator can change that number for their own server. The figure lives in one Ruby constant, app/validators/status_length_validator.rb:
class StatusLengthValidator < ActiveModel::Validator
MAX_CHARS = 500
URL_PLACEHOLDER_CHARS = 23
URL_PLACEHOLDER = 'x' * 23There is no admin setting, no environment variable and no web form in upstream Mastodon that moves MAX_CHARS. A server that runs a longer limit is running patched code. That is why "the Mastodon character limit" is a question about which server you are posting from rather than a question about Mastodon.
When you go over, the validator adds the error from the statuses.over_character_limit translation key, which in English reads "character limit of %{max} exceeded". The %{max} is interpolated from whatever MAX_CHARS holds on that server, so the error message itself tells you the local number.
What changes the 500 character default?
Three things, in descending order of how common they are.
A fork changes it. The glitch-soc fork, which many long-running servers use, replaces the hardcoded constant with an environment variable:
MAX_CHARS = (ENV['MAX_TOOT_CHARS'] || 500).to_iAn operator sets MAX_TOOT_CHARS=11000 in their environment file and the whole server posts at 11,000. Upstream Mastodon has never adopted that variable, so the same knob does not exist on an unmodified install.
A patch changes it. Operators running vanilla Mastodon edit the constant directly and rebuild. This is the oldest method and it survives because the change is one line.
A version bump does not change it. Mastodon has shipped 500 as the upstream default since the project's early releases, and it has not moved through any of the 4.x series.
The reason there is no admin toggle is worth understanding, because it explains why the situation will not be tidied up. A Mastodon server does not own the posts it displays. It receives most of them from other servers, and it has no mechanism to reject one for being too long. Mastodon's lead developer has rejected patches that make the limit configurable, arguing that the interface is designed around one number and that the base level of functionality should be the same on every server. Keeping the number in source code makes raising it a deliberate act by someone who edits and redeploys.

How different are real Mastodon servers?
Very. These figures came from each server's own /api/v2/instance endpoint on 12 September 2026.
| Server | Software version | max_characters | characters_reserved_per_url | max_media_attachments |
|---|---|---|---|---|
| mastodon.social | 4.8.0-alpha.2 | 500 | 23 | 4 |
| mastodon.online | 4.8.0-nightly | 500 | 23 | 4 |
| fosstodon.org | 4.7.1 | 500 | 23 | 4 |
| mas.to | 4.7.1 | 1000 | 23 | 4 |
| infosec.exchange | 4.8.0-alpha.2+glitch | 11000 | 23 | 4 |
| todon.eu | 4.7.1+todon | 13120 | 23 | 4 |
The +glitch suffix on infosec.exchange is the tell. It is running the fork, so MAX_TOOT_CHARS applies, and its limit is 22 times the flagship server's. Two servers on the identical 4.7.1 release report 500 and 1,000 respectively, which is the clearest evidence that the version number tells you nothing about the limit.
One column does not move. characters_reserved_per_url is 23 everywhere, because URL_PLACEHOLDER_CHARS sits in the same file as MAX_CHARS and nobody bothers to patch it. Neither does max_media_attachments, fixed by Status::MEDIA_ATTACHMENTS_LIMIT = 4 in the status model.

What counts as a character on Mastodon?
The validator counts grapheme clusters, not bytes and not code points:
AdaptlyPost
Start 7-Day FREE Trial
All-platform analytics
Social Inbox
AI-powered assistant
def countable_length(str)
str.each_grapheme_cluster.size
endA grapheme cluster is what a reader sees as one character. The four-person family emoji is seven code points and 25 UTF-8 bytes, and Mastodon charges you 1 for it. This is the opposite of how Threads counts emoji against its own 500 limit, where Meta bills each emoji as its UTF-8 byte length and that same family emoji costs 25. Two platforms, the same headline number, a 24 character difference on one emoji.
Before counting, the validator rewrites two kinds of entity.
Every URL is replaced by URL_PLACEHOLDER, which is literally 23 x characters. A three character link and a 400 character tracking URL both cost 23. Shortening a link before you post buys you nothing on Mastodon.
Every mention is trimmed to its local part. The rewrite is "@#{entity[:screen_name].split('@').first}", so @someone@long.server.example.org is counted as @someone, eight characters instead of 32. Replying into a thread with six remote participants costs far less than the visible text suggests.
The content warning is not free. combined_text joins the spoiler field to the rewritten body before counting:
def combined_text(status)
[status.spoiler_text, countable_text(status.text)].join
endA 60 character content warning leaves 440 characters for the post on a standard server. Nothing in the composer says so.
One more rule decides who gets checked at all. The validator opens with return unless status.local? && !status.reblog?, so it only runs on posts created on that server. A 9,000 character post federated in from a glitch-soc server is stored and displayed in full on a 500 character server, because the length rule is enforced at authoring time and never on receipt. That asymmetry is native to how the fediverse passes posts between servers rather than a bug in any one of them.
How do you read a server's limit before posting?
Ask the server. Mastodon's instance serializer publishes the live constants, so no guessing is required:
"statuses": {
"max_characters": 500,
"max_media_attachments": 4,
"characters_reserved_per_url": 23
}That block comes from GET /api/v2/instance under configuration, and the serializer builds it straight from StatusLengthValidator::MAX_CHARS, Status::MEDIA_ATTACHMENTS_LIMIT and StatusLengthValidator::URL_PLACEHOLDER_CHARS. Whatever an operator patched, this endpoint reports it.
Any tool that posts to more than one server should read this on connect and cache it per server, then count graphemes rather than string length, substitute 23 for each URL, and add the content warning field to the total. A counter that does text.length in JavaScript is wrong on three separate counts, since it splits emoji into surrogate pairs, charges full price for URLs, and ignores the spoiler field.
The errors do not all push the same way, which is what makes them hard to notice. Grapheme counting and the 23 character URL price both work in your favor, so a naive counter that reports 490 may be a post the server accepts at 430. The content warning works against you, so the same naive counter reporting 490 on the body of a post carrying a 60 character warning is a post the server rejects at 550. Fetching max_characters once per server and counting the way the validator counts removes the whole class of problem, and /api/v2/instance needs no access token, so there is nothing to arrange before you can ask.
This is the same class of problem as the byte offsets Bluesky requires in a post's facets, where the text you see and the text the protocol measures are indexed differently. If you are weighing the two networks against each other, the length rules are one of the sharper differences in how Mastodon and Bluesky compare.
Frequently asked questions
Is the Mastodon character limit 500 or 5,000?
Upstream Mastodon ships 500. Servers running the glitch-soc fork set their own value through the MAX_TOOT_CHARS environment variable, and values of 1,000, 5,000 and 11,000 are all in production today. Check /api/v2/instance for the server you post from.
Can an admin change the character limit from the Mastodon dashboard?
No. There is no setting in the admin interface. Upstream requires editing MAX_CHARS in app/validators/status_length_validator.rb and rebuilding; glitch-soc reads the MAX_TOOT_CHARS environment variable at boot.
How many characters does a link cost on Mastodon?
Exactly 23, set by URL_PLACEHOLDER_CHARS. The validator swaps every extracted URL for a 23 character placeholder before counting, so link length has no effect on your remaining budget.
AdaptlyPost
Start 7-Day FREE Trial
All-platform analytics
Social Inbox
AI-powered assistant
Does the content warning count toward the limit?
Yes. The combined_text method joins the spoiler text to the post body before the count runs, so a long content warning eats directly into the characters available for the post.
Do emoji count as one character on Mastodon?
Yes. The count is over grapheme clusters, so a skin-toned emoji or a multi-person family emoji costs 1 no matter how many code points or bytes it contains.
What happens if a long post federates to a 500 character server?
It arrives and displays in full. The length validator runs only on locally authored posts, so a server with a 500 character limit still stores and renders an 11,000 character post received from elsewhere.
Why is a JavaScript character counter wrong for Mastodon posts?
A counter that runs text.length in JavaScript splits a multi-person emoji into its separate surrogate pairs, charges full length for every URL instead of the flat 23 characters Mastodon uses, and ignores the content warning field entirely. Mastodon counts grapheme clusters, substitutes a 23 character placeholder for each URL, and adds the spoiler text to the total before checking the limit. The two counting methods can disagree in both directions, so a naive count of 490 could belong to a post the server accepts at 430 or rejects at 550, depending on what's in it.
How much cheaper is mentioning someone on a remote server than it looks?
Mastodon trims every mention to its local part before counting, so @someone@long.server.example.org costs eight characters instead of the 32 visible in the composer. A reply in a thread with several remote participants can look long in the editor but cost far less against the limit than the displayed text suggests.
How high does the character limit go on real Mastodon servers?
todon.eu reports 13,120 characters through its /api/v2/instance endpoint and infosec.exchange reports 11,000, against 500 on mastodon.social. Both reach those numbers by running a fork with the limit set in the environment, not through any option upstream Mastodon offers.
Why doesn't Mastodon offer a per-server dropdown for the character limit?
Mastodon's lead developer has turned down patches that make the limit configurable, on the grounds that the interface is designed around one number and the base level of functionality should be the same on every server. Federation compounds it, since the length validator runs only on locally authored posts and every other server stores and renders whatever arrives. Operators who want a longer limit edit the constant themselves or run a fork such as glitch-soc.
Put this into practice with AdaptlyPost
Was This Article Helpful?
Let us know what you think!
See us more often in Google
One click marks AdaptlyPost as a preferred source, so our articles sit higher in your Top Stories, AI Mode, and AI Overviews.
Before you go...
AdaptlyPost
Schedule your content across all platforms
Manage all your social media accounts in one place with AdaptlyPost.
All-platform analytics
Social Inbox
AI-powered assistant
Related Glossary Terms


Why the Bluesky Image Size Limit Is 2,000,000 Bytes
The Bluesky image size limit is 2,000,000 bytes per post image, set by maxSize in the images lexicon. Avatars and banners stop at 1,000,000 bytes.


What Happens to a Threads Ghost Post After 24 Hours
A Threads ghost post is a text-only post Meta archives after 24 hours. Replies can route to your inbox, and the API creates one with is_ghost_post=true.


What Every IPTC Digital Source Type Code Means
Every IPTC digital source type QCode in plain English: 17 live terms, 3 retired, and what social platforms do with the value after upload.
Related Articles


Why the Threads Character Limit Counts Emoji as UTF-8 Bytes
The Threads character limit is 500, but Meta counts each emoji as its UTF-8 byte length, so one family emoji costs 25. Here is how to count a post correctly.


Why the TikTok Caption Character Limit Is Measured in UTF-16 Runes
The TikTok caption character limit is 2200 UTF-16 runes for video and 90 for a photo title. Runes are not characters, and one emoji can cost eleven.


C2PA in Plain English: What Are Content Credentials?
C2PA manifests explained: what are Content Credentials, what a claim signature proves, and which networks say anything about the manifest after an upload.

