--- title: "How to Install and Configure Memcached on Ubuntu 24.04" description: "Install Memcached on Ubuntu 24.04, size its memory, threads and connections, keep it off the public internet, cache data from Python and PHP and read its stats." category: "Performance Optimization" language: en source: https://cubepath.com/docs/performance-optimization/caching-with-memcached-configuration updated: 2026-09-25 --- # How to Install and Configure Memcached on Ubuntu 24.04 Memcached is a simple, multithreaded in-memory key-value cache. It has no persistence, no replication and no complex data types, and that simplicity is exactly why it is fast and predictable for caching query results, rendered pages and sessions. In this tutorial you will install Memcached on Ubuntu 24.04, configure its memory, connection and thread limits, keep it private, use it from Python and PHP, and read its statistics to check that the cache is effective. ## Prerequisites - A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 1 GB of RAM. - A non-root user with `sudo` privileges. - Optionally, PHP-FPM if you want to follow the PHP session example in Step 6. ## Step 1 - Installing Memcached Install Memcached from the Ubuntu repository together with `netcat-openbsd`, which you will use to query its statistics: ```bash sudo apt update sudo apt install memcached netcat-openbsd ``` The package creates the `memcached` systemd service, starts it and enables it at boot. Check its status: ```bash sudo systemctl status memcached --no-pager ``` ```output ● memcached.service - memcached daemon Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: enabled) Active: active (running) since Thu 2026-09-25 11:02:44 UTC; 6s ago ... ``` Confirm which address and port it listens on: ```bash sudo ss -ltnp | grep 11211 ``` ```output LISTEN 0 1024 127.0.0.1:11211 0.0.0.0:* users:(("memcached",pid=3120,fd=26)) ``` By default Memcached on Ubuntu only listens on `127.0.0.1`, so it is not reachable from other machines. ## Step 2 - Configuring memory, connections and threads On Ubuntu, the service reads its command-line options from `/etc/memcached.conf`, one option per line. Open it: ```bash sudo nano /etc/memcached.conf ``` Adjust or add these lines. Options that are commented out with `#` use their built-in default: ```text # Run as a daemon and log to this file -d logfile /var/log/memcached.log # Memory for cached items, in megabytes (default 64) -m 512 # TCP port, and disable UDP -p 11211 -U 0 # User and listen address -u memcache -l 127.0.0.1 # Maximum simultaneous connections (default 1024) -c 2048 # Worker threads (default 4) -t 4 -P /var/run/memcached/memcached.pid ``` What each setting controls: - **`-m`**: the memory budget for stored items. When it is full, Memcached evicts the least recently used items to make room. The default of 64 MB is too small for most real workloads. Give Memcached what is left after the operating system, your application and your database have enough memory; on a 4 GB server that also runs a database, 512 MB to 1 GB is a sensible start. - **`-c`**: the maximum number of client connections. Size it for the number of application workers on all servers that connect, with some margin. For example, 3 servers with 100 PHP-FPM workers each, each holding one persistent connection, need at least 300. - **`-t`**: worker threads. The default of 4 is right for most servers. Raise it only on machines with many cores that handle very high request rates; more threads than cores does not help. - **`-U 0`**: disables the UDP listener. UDP is rarely used by clients and exposed UDP Memcached servers have been abused for large DDoS amplification attacks. Recent versions already disable UDP by default; setting it explicitly documents the intent. - **`-l`**: the listen address. Keep `127.0.0.1` when the application runs on the same server. Restart the service to apply the changes: ```bash sudo systemctl restart memcached ``` Verify the effective settings by asking Memcached itself. The `quit` command makes the server close the connection, so `nc` exits on its own: ```bash printf 'stats settings\r\nquit\r\n' | nc 127.0.0.1 11211 | grep -E "maxbytes|maxconns|udpport|num_threads|item_size_max" ``` ```output STAT maxbytes 536870912 STAT maxconns 2048 STAT udpport 0 STAT num_threads 4 STAT item_size_max 1048576 ``` `536870912` bytes is 512 MB. `item_size_max` shows the largest value Memcached accepts, 1 MB by default. You can raise it with `-I 2m`, but large values are usually better stored elsewhere or compressed by the client. ## Step 3 - Testing Memcached with the text protocol Memcached speaks a simple text protocol, which makes it easy to test by hand. Store a key named `greeting` with flags `0`, a TTL of `300` seconds and a 5-byte value, read it back and delete it: ```bash printf 'set greeting 0 300 5\r\nhello\r\nget greeting\r\ndelete greeting\r\nquit\r\n' | nc 127.0.0.1 11211 ``` ```output STORED VALUE greeting 0 5 hello END DELETED ``` `STORED` confirms the write, the `VALUE ... END` block is the read, and `DELETED` confirms the removal. If you get no output at all, Memcached is not listening on that address; recheck the `-l` line and the service status. ## Step 4 - Allowing access from application servers (optional) When your application runs on other servers, bind Memcached to the server's **private** IP address as well as localhost. Memcached has no authentication in the default Ubuntu build, so the network is your only access control: never listen on a public address. Edit the listen line in `/etc/memcached.conf`, replacing `your_private_ip`: ```bash sudo nano /etc/memcached.conf ``` ```text -l 127.0.0.1,your_private_ip ``` Restart Memcached and allow only your application servers through UFW. Repeat the `ufw allow` command for each server, replacing `app_server_ip` with its private address: ```bash sudo systemctl restart memcached sudo ufw allow from app_server_ip to any port 11211 proto tcp ``` From an application server, check that it can reach the cache: ```bash printf 'version\r\nquit\r\n' | nc your_private_ip 11211 ``` ```output VERSION 1.6.24 ``` > Warning: If `-l` is removed or set to `0.0.0.0`, Memcached listens on every interface and anyone who can reach port 11211 can read, change or flush your cache. Keep it on localhost or a private network, and keep UFW rules limited to known clients. ## Step 5 - Caching data from Python The typical way to use Memcached is the **cache-aside** pattern: look up the key; on a miss, load the data from the database, store it with a TTL and return it. Install the `pymemcache` client from the Ubuntu repository: ```bash sudo apt install python3-pymemcache ``` Create a small demonstration script: ```bash nano ~/memcached_demo.py ``` The `slow_database_query` function stands in for a real query that takes half a second: ```python import json import time from pymemcache.client.base import Client cache = Client(("127.0.0.1", 11211), connect_timeout=1, timeout=0.5) def slow_database_query(user_id): time.sleep(0.5) # simulate a slow SQL query return {"id": user_id, "name": f"User {user_id}", "plan": "pro"} def get_user(user_id, ttl=300): key = f"user:{user_id}" cached = cache.get(key) if cached is not None: return json.loads(cached), "hit" user = slow_database_query(user_id) cache.set(key, json.dumps(user), expire=ttl) return user, "miss" def invalidate_user(user_id): # Call this after updating the user in the database cache.delete(f"user:{user_id}") if __name__ == "__main__": for _ in range(3): start = time.perf_counter() user, status = get_user(7) print(f"{status:4} {(time.perf_counter() - start) * 1000:7.1f} ms {user}") # Fetch several keys in one round trip print(cache.get_many(["user:7", "user:8"])) ``` Run it: ```bash python3 ~/memcached_demo.py ``` ```output miss 502.6 ms {'id': 7, 'name': 'User 7', 'plan': 'pro'} hit 0.3 ms {'id': 7, 'name': 'User 7', 'plan': 'pro'} hit 0.2 ms {'id': 7, 'name': 'User 7', 'plan': 'pro'} {'user:7': b'{"id": 7, "name": "User 7", "plan": "pro"}'} ``` Only the first call hits the "database". `get_many` returns just the keys that exist (`user:8` was never stored), and it fetches them in a single network round trip, which matters when a page needs dozens of cached objects. Keep these rules in mind when you design keys: - Keys are limited to 250 bytes and cannot contain spaces or control characters. Hash long identifiers (for example with SHA-256) before using them in a key. - Always set a TTL. Memcached evicts by LRU when memory is full, but the TTL is what keeps stale data from being served. - Treat every miss as normal. Memcached can be restarted or can evict any key at any time, so the application must always be able to rebuild the value. If you run several Memcached servers, use `pymemcache.client.hash.HashClient` with the list of servers. The client hashes each key to one server, so the total cache size is the sum of all servers and losing one server only loses its share of the keys. ## Step 6 - Storing PHP sessions in Memcached (optional) Storing PHP sessions in Memcached lets several web servers share them. Install the PHP extension for your PHP version (8.3 on Ubuntu 24.04): ```bash sudo apt install php8.3-memcached ``` Open the PHP-FPM configuration file: ```bash sudo nano /etc/php/8.3/fpm/php.ini ``` Find the `session.save_handler` and `session.save_path` directives and set them as follows. With the `memcached` extension, the save path is a plain `host:port` list without a protocol prefix: ```ini session.save_handler = memcached session.save_path = "127.0.0.1:11211" ``` Restart PHP-FPM: ```bash sudo systemctl restart php8.3-fpm ``` Check that the setting is active in the FPM configuration: ```bash php-fpm8.3 -i | grep -E "^session.save_(handler|path)" ``` ```output session.save_handler => memcached => memcached session.save_path => 127.0.0.1:11211 => 127.0.0.1:11211 ``` > Note: Sessions stored only in Memcached are lost when it restarts or evicts them, which logs users out. That is acceptable for many sites. If it is not for yours, store sessions in Redis with persistence or in your database instead. For WordPress, an object cache plugin with a Memcached backend uses the same `php8.3-memcached` extension and the same server. ## Step 7 - Monitoring hit rate, evictions and connections Memcached exposes its counters through the `stats` command: ```bash printf 'stats\r\nquit\r\n' | nc 127.0.0.1 11211 | grep -E "curr_connections|listen_disabled_num|get_hits|get_misses|evictions|curr_items| bytes |limit_maxbytes" ``` ```output STAT curr_connections 38 STAT listen_disabled_num 0 STAT get_hits 482113 STAT get_misses 31207 STAT curr_items 20481 STAT bytes 187342112 STAT limit_maxbytes 536870912 STAT evictions 0 ``` How to read these values: - **Hit rate**: `get_hits / (get_hits + get_misses)`. Here it is about 94 percent. A low hit rate means short TTLs, keys that are never reused, or a cache that is too small. - **`evictions`**: items removed before their TTL expired because memory was full. A steadily growing number, together with a falling hit rate, means `-m` is too small. - **`bytes` and `limit_maxbytes`**: current memory used by items and the configured limit. - **`listen_disabled_num`**: how many times Memcached stopped accepting new connections because it reached the `-c` limit. Any value above zero means you should raise `-c`. These counters reset when the service restarts. For continuous tracking, feed them into your monitoring system, for example with the Prometheus `memcached_exporter` or the Memcached integration of your monitoring agent. ## Troubleshooting **Clients time out or get `Connection refused`.** Check that the service is running with `systemctl status memcached`, that `ss -ltnp | grep 11211` shows the expected address, and that UFW allows the client's IP. Look at `/var/log/memcached.log` and `sudo journalctl -u memcached` for startup errors caused by a mistyped option. **`SERVER_ERROR object too large for cache`.** The value is bigger than `item_size_max` (1 MB by default). Compress the value in the client, split it, or raise the limit with `-I` in `/etc/memcached.conf`. **High evictions even though `bytes` is below the limit.** Memcached allocates memory in slab classes by item size. If your item sizes change a lot over time, memory may be assigned to classes you no longer use. Recent versions rebalance slabs automatically; if evictions persist, increase `-m` and check which item sizes dominate with `printf 'stats slabs\r\nquit\r\n' | nc 127.0.0.1 11211`. ## Conclusion You installed Memcached on Ubuntu 24.04, gave it a proper memory, connection and thread budget, kept it on localhost or a private network, used it from Python with the cache-aside pattern and from PHP as a session store, and learned which statistics tell you whether the cache is working. Next, you can add more Memcached servers behind a hashing client as your cache grows, connect Memcached metrics to your monitoring stack, or compare it with Redis if you need persistence, replication or richer data types.