← Voltar aos artigos

php-fpm · configuração · servidor · opcache

Mudei o php.ini e nada mudou: por que o PHP-FPM ignora sua alteração

Publicado em 18/09/2026 · 10 min de leitura

Você editou o php.ini, salvou, recarregou a página — e o valor continua o mesmo. Quase sempre a causa é uma destas duas: você editou o php.ini errado (cada SAPI do PHP tem o seu, e o do terminal não é o do site) ou você não recarregou o PHP-FPM (o arquivo é lido uma única vez, quando o processo sobe). O comando php --ini, que todo tutorial manda rodar, mostra o arquivo do CLI — justamente o que a sua página não usa. Abaixo: por que funciona assim, como descobrir o arquivo certo em trinta segundos, a hierarquia completa que decide o valor final, e por que às vezes nem o arquivo certo resolve.

O mecanismo: uma SAPI, um php.ini

SAPI (Server API) é o modo como o PHP foi acionado. O mesmo PHP instalado na máquina roda em modos diferentes: cli quando você digita php script.php no terminal, fpm-fcgi quando o nginx repassa uma requisição ao PHP-FPM. Cada modo carrega sua própria configuração — o que faz sentido, porque as necessidades são opostas: um script de terminal pode rodar por horas e consumir muita memória; uma página web não deve.

Em instalações por pacote (Debian/Ubuntu), a separação é literal, um diretório por SAPI:

/etc/php/8.3/cli/php.ini     ← o que o `php --ini` mostra
/etc/php/8.3/fpm/php.ini     ← o que o seu SITE usa
/etc/php/8.3/fpm/conf.d/     ← arquivos extras, carregados depois
/etc/php/8.3/fpm/pool.d/www.conf   ← configuração do pool (mais específica ainda)

Em imagens Docker oficiais o layout é outro (um /usr/local/etc/php/php.ini compartilhado + conf.d), e em painéis de hospedagem pode ser outro ainda. Por isso a resposta nunca é decorar caminhos — é perguntar ao próprio site qual arquivo ele carregou.

O segundo pilar do mecanismo: o php.ini é lido quando o processo inicia. O master do PHP-FPM lê a configuração ao subir e os workers nascem já com aqueles valores. Enquanto o master continuar vivo, ele não relê arquivo nenhum — você pode editar e salvar quantas vezes quiser que nada muda. É a mesma lógica de qualquer daemon: configuração nova exige avisar o processo.

Diagnóstico: pergunte ao site, não ao terminal

Este é o passo que economiza a tarde inteira. Crie um arquivo temporário na raiz pública e abra pelo navegador (não pelo terminal):

<?php
phpinfo();

Na página, procure três campos no topo:

  • Server API — deve dizer FPM/FastCGI. Se disser Command Line Interface, você rodou pelo terminal e está vendo a configuração errada.
  • Loaded Configuration Fileeste é o arquivo que importa. É o php.ini que a sua página realmente carregou.
  • Scan this dir for additional .ini files / Additional .ini files parsed — os arquivos do conf.d que são lidos depois e podem sobrescrever o principal.

Compare com o que o terminal diz (php --ini) e a diferença aparece na hora. Se os dois apontam arquivos diferentes, você achou a causa.

Para checar um valor específico sem expor tudo, uma linha basta — e ela mostra o valor efetivo, já com todas as camadas aplicadas:

<?php
echo ini_get('memory_limit');   // o que está valendo AGORA, nesta requisição
evite
# o caminho que parece certo e não é
php --ini
# Loaded Configuration File: /etc/php/8.3/cli/php.ini

sudo nano /etc/php/8.3/cli/php.ini     # ← ini do TERMINAL
# altera memory_limit, salva, recarrega a página… nada muda
prefira
# 1. descubra o ini do FPM pelo phpinfo() aberto no NAVEGADOR
#    Loaded Configuration File: /etc/php/8.3/fpm/php.ini

sudo nano /etc/php/8.3/fpm/php.ini     # ← ini do SITE

sudo php-fpm8.3 -t                     # 2. valide a configuração
sudo systemctl reload php8.3-fpm       # 3. aplique (graceful)
# confira de novo no phpinfo/ini_get

A hierarquia: quem ganha de quem

Mesmo no arquivo certo, o valor pode estar sendo sobrescrito depois. O PHP monta a configuração em camadas, e a última que fala vence:

1. php.ini principal

A base. É o arquivo que o Loaded Configuration File aponta.

; /etc/php/8.3/fpm/php.ini
memory_limit = 128M

2. Arquivos do conf.d

Lidos depois, em ordem alfabética do nome. Por isso arquivos costumam ser prefixados com números (99-overrides.ini vence 10-opcache.ini). Instalar uma extensão joga um arquivo aqui — e ele pode sobrescrever o que você editou no principal.

; /etc/php/8.3/fpm/conf.d/99-app.ini
memory_limit = 256M      ; ← agora vale 256M

3. Configuração do pool (FPM)

Mais específica ainda: vale só para aquele pool. Duas formas, com uma diferença crucial.

; /etc/php/8.3/fpm/pool.d/www.conf
php_value[memory_limit] = 512M        ; pode ser mudado por ini_set
php_admin_value[memory_limit] = 512M  ; NÃO pode ser mudado por ini_set

4. ini_set() em runtime

A camada mais específica: vale só para aquela requisição, a partir daquela linha.

ini_set('memory_limit', '1G');   // só nesta execução

A regra final

Da mais genérica para a mais específica: php.ini → conf.d → pool → ini_set. Quando o valor não é o que você espera, a pergunta certa é "quem falou por último?" — e o ini_get() responde.

echo ini_get('memory_limit');   // o vencedor da disputa

A diferença entre php_value e php_admin_value não é detalhe de estilo — está documentada no próprio arquivo de exemplo que acompanha o FPM: "php_admin_value/php_admin_flag — these directives won't be overwritten by PHP call ini_set". Ou seja, se o administrador definiu php_admin_value[memory_limit], o seu ini_set('memory_limit', ...) no código não tem efeito e você fica procurando bug onde não há. É o mecanismo usado em hospedagem compartilhada para impor limites.

ini_set() não muda tudo

Mesmo sem php_admin_value no caminho, há diretivas que ini_set() simplesmente não consegue alterar — e ele falha em silêncio, devolvendo false sem lançar erro. Cada diretiva tem um "modo" que define onde pode ser definida: PHP_INI_ALL (em qualquer lugar, inclusive runtime), PHP_INI_PERDIR (só em php.ini/pool/.user.ini) e PHP_INI_SYSTEM (só em php.ini/pool). Testado:

Diretiva ini_set() Por quê
memory_limit ✅ muda PHP_INI_ALL
max_execution_time ✅ muda PHP_INI_ALL
display_errors ✅ muda PHP_INI_ALL
upload_max_filesize false PHP_INI_PERDIR
post_max_size false PHP_INI_PERDIR
disable_functions false PHP_INI_SYSTEM

Faz sentido: o tamanho máximo de upload precisa ser conhecido antes de o PHP começar a receber o corpo da requisição — quando o seu script roda, o upload já foi aceito ou recusado. Por isso ini_set('upload_max_filesize', '64M') nunca funcionou para ninguém. Se ini_set() devolveu false, a diretiva exige arquivo + reload.

O terceiro motivo (e uma distinção importante)

Existe um caso que chega ao Google com a mesma frase — "mudei e não fez efeito" — mas tem outra causa: o OPcache. Vale separar bem as duas, porque confundi-las custa horas:

  • O OPcache não guarda valores do php.ini. Se você mudou uma diretiva e recarregou o FPM, o OPcache não tem nada a ver com isso.
  • O OPcache guarda o bytecode do seu código PHP. Se você editou um arquivo .php e a mudança não aparece, aí sim o suspeito é ele — especialmente com opcache.validate_timestamps = 0, configuração comum em produção por performance, que manda o PHP nunca checar se o arquivo mudou.

Nesse caso, o conserto é o mesmo comando: systemctl reload php8.3-fpm limpa o cache de bytecode, porque os workers novos começam com a memória compartilhada revalidada. É por isso que "recarregar o FPM" resolve tanta coisa aparentemente diferente.

Você aumentou memory_limit para 512M. No terminal, php -r "echo ini_get('memory_limit');" mostra 512M. No site, continua 128M. O que aconteceu?

Ver resposta

Resposta certa: Você editou o php.ini do CLI; o do FPM continua com o valor antigo (e/ou faltou reload)

O terminal e o site usam SAPIs diferentes, cada uma com seu php.ini — o php --ini aponta o do CLI. Alterar lá muda só os scripts de terminal. Abra um phpinfo() pelo navegador, leia o Loaded Configuration File, edite aquele arquivo e rode systemctl reload php8.3-fpm. E descarte o OPcache como suspeito: ele guarda bytecode do seu código, não valores de configuração.

Resumo de decisão

Sintoma Causa provável Conserto
Muda no terminal, não no site php.ini do CLI ≠ do FPM Achar o do FPM no phpinfo()
Arquivo certo e nada muda Faltou recarregar php-fpm -t + systemctl reload
Valor volta ao antigo sozinho Sobrescrito no conf.d ou no pool Conferir a ordem; ini_get() mostra o vencedor
ini_set() não surte efeito php_admin_value no pool Alterar no pool (ou pedir ao admin)
ini_set() devolve false Diretiva PHP_INI_PERDIR/SYSTEM Só via arquivo + reload
Mudei o código e não mudou OPcache com validate_timestamps=0 systemctl reload php8.3-fpm

Em uma frase: descubra o arquivo pelo phpinfo() servido na web, edite aquele, valide com -t, recarregue com reload e confirme com ini_get() — nessa ordem, você nunca mais mexe no escuro.

no manualThe configuration file

A página do arquivo de configuração explica a ordem de leitura do php.ini, os arquivos adicionais do conf.d e como o PHP decide qual carregar em cada SAPI.

estudar na árvore →
no manualWhere a configuration setting may be set

Esta é a referência dos modos PHP_INI_ALL, PHP_INI_PERDIR e PHP_INI_SYSTEM — ela diz, diretiva por diretiva, onde cada uma pode ser definida. É o que explica por que ini_set() funciona para umas e não para outras.

estudar na árvore →
no manualRuntime Configuration

As diretivas do OPcache (validate_timestamps, revalidate_freq, enable_cli) determinam quando o PHP relê seus arquivos. Entendê-las separa o "configuração não aplicou" do "código não atualizou".

estudar na árvore →

Leve o estudo além do artigo

O manual inteiro do PHP como uma jornada: progresso por tópico, anotações e leitura embutida.